Browse Source

Merge branch 'master' into feature/fix-encoders-import-bug

pull/12488/head
Mateus Alves de Oliveira 5 months ago
committed by GitHub
parent
commit
5b42456d93
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      .github/workflows/deploy-docs.yml
  2. 2
      .github/workflows/publish.yml
  3. 2
      .pre-commit-config.yaml
  4. 1
      README.md
  5. 8
      docs/de/docs/advanced/async-tests.md
  6. 91
      docs/de/docs/advanced/security/http-basic-auth.md
  7. 12
      docs/de/docs/tutorial/response-status-code.md
  8. 3
      docs/en/data/sponsors.yml
  9. 1
      docs/en/data/sponsors_badge.yml
  10. 16
      docs/en/docs/advanced/additional-responses.md
  11. 52
      docs/en/docs/advanced/additional-status-codes.md
  12. 120
      docs/en/docs/advanced/advanced-dependencies.md
  13. 16
      docs/en/docs/advanced/async-tests.md
  14. 20
      docs/en/docs/advanced/behind-a-proxy.md
  15. 12
      docs/en/docs/advanced/dataclasses.md
  16. 24
      docs/en/docs/advanced/events.md
  17. 12
      docs/en/docs/advanced/middleware.md
  18. 4
      docs/en/docs/advanced/openapi-webhooks.md
  19. 90
      docs/en/docs/advanced/security/http-basic-auth.md
  20. 528
      docs/en/docs/advanced/security/oauth2-scopes.md
  21. 1
      docs/en/docs/deployment/cloud.md
  22. 4
      docs/en/docs/how-to/conditional-openapi.md
  23. 16
      docs/en/docs/how-to/configure-swagger-ui.md
  24. 28
      docs/en/docs/how-to/custom-docs-ui-assets.md
  25. 24
      docs/en/docs/how-to/custom-request-and-route.md
  26. 20
      docs/en/docs/how-to/extending-openapi.md
  27. 4
      docs/en/docs/how-to/graphql.md
  28. 162
      docs/en/docs/how-to/separate-openapi-schemas.md
  29. 25
      docs/en/docs/img/sponsors/render-banner.svg
  30. 24
      docs/en/docs/img/sponsors/render.svg
  31. 40
      docs/en/docs/python-types.md
  32. 82
      docs/en/docs/release-notes.md
  33. 62
      docs/en/docs/tutorial/background-tasks.md
  34. 103
      docs/en/docs/tutorial/body-fields.md
  35. 92
      docs/en/docs/tutorial/body.md
  36. 180
      docs/en/docs/tutorial/dependencies/index.md
  37. 16
      docs/en/docs/tutorial/encoder.md
  38. 28
      docs/en/docs/tutorial/first-steps.md
  39. 12
      docs/en/docs/tutorial/response-status-code.md
  40. 2
      docs/en/docs/tutorial/security/oauth2-jwt.md
  41. 4
      docs/en/docs/tutorial/static-files.md
  42. 6
      docs/en/overrides/main.html
  43. 104
      docs/es/docs/tutorial/cookie-params.md
  44. 57
      docs/fr/docs/python-types.md
  45. 16
      docs/fr/docs/tutorial/background-tasks.md
  46. 24
      docs/fr/docs/tutorial/body.md
  47. 4
      docs/fr/docs/tutorial/debugging.md
  48. 274
      docs/fr/docs/tutorial/path-params-numeric-validations.md
  49. 56
      docs/fr/docs/tutorial/query-params-str-validations.md
  50. 24
      docs/fr/docs/tutorial/query-params.md
  51. 33
      docs/ko/docs/advanced/response-change-status-code.md
  52. 53
      docs/ko/docs/advanced/response-cookies.md
  53. 67
      docs/ko/docs/advanced/response-directly.md
  54. 37
      docs/ko/docs/advanced/wsgi.md
  55. 34
      docs/ko/docs/benchmarks.md
  56. 83
      docs/ko/docs/fastapi-cli.md
  57. 131
      docs/ko/docs/tutorial/metadata.md
  58. 32
      docs/pl/docs/tutorial/first-steps.md
  59. 20
      docs/pt/docs/advanced/behind-a-proxy.md
  60. 344
      docs/pt/docs/advanced/custom-response.md
  61. 96
      docs/pt/docs/advanced/middleware.md
  62. 194
      docs/pt/docs/advanced/openapi-callbacks.md
  63. 188
      docs/pt/docs/advanced/websockets.md
  64. 132
      docs/pt/docs/tutorial/metadata.md
  65. 176
      docs/pt/docs/tutorial/request-files.md
  66. 539
      docs/pt/docs/tutorial/security/simple-oauth2.md
  67. 359
      docs/pt/docs/tutorial/sql-databases.md
  68. 2
      fastapi/__init__.py
  69. 30
      fastapi/dependencies/utils.py
  70. 4
      requirements-docs.txt
  71. 4
      requirements-tests.txt
  72. 2
      requirements.txt
  73. 107
      tests/test_multipart_installation.py

2
.github/workflows/deploy-docs.yml

@ -64,7 +64,7 @@ jobs:
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 ) }}
# TODO: Use v3 when it's fixed, probably in v3.11
# https://github.com/cloudflare/wrangler-action/issues/307
uses: cloudflare/wrangler-action@v3.9
uses: cloudflare/wrangler-action@v3.11
# uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}

2
.github/workflows/publish.yml

@ -35,7 +35,7 @@ jobs:
TIANGOLO_BUILD_PACKAGE: ${{ matrix.package }}
run: python -m build
- name: Publish
uses: pypa/gh-action-pypi-publish@v1.10.3
uses: pypa/gh-action-pypi-publish@v1.11.0
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}

2
.pre-commit-config.yaml

@ -14,7 +14,7 @@ repos:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.7.0
rev: v0.7.1
hooks:
- id: ruff
args:

1
README.md

@ -56,6 +56,7 @@ The key features are:
<a href="https://www.mongodb.com/developer/languages/python/python-quickstart-fastapi/?utm_campaign=fastapi_framework&utm_source=fastapi_sponsorship&utm_medium=web_referral" target="_blank" title="Simplify Full Stack Development with FastAPI & MongoDB"><img src="https://fastapi.tiangolo.com/img/sponsors/mongodb.png"></a>
<a href="https://zuplo.link/fastapi-gh" target="_blank" title="Zuplo: Scale, Protect, Document, and Monetize your FastAPI"><img src="https://fastapi.tiangolo.com/img/sponsors/zuplo.png"></a>
<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>
<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>
<a href="https://github.com/deepset-ai/haystack/" target="_blank" title="Build powerful search from composable, open source building blocks"><img src="https://fastapi.tiangolo.com/img/sponsors/haystack-fastapi.svg"></a>
<a href="https://databento.com/" target="_blank" title="Pay as you go for market data"><img src="https://fastapi.tiangolo.com/img/sponsors/databento.svg"></a>
<a href="https://speakeasy.com?utm_source=fastapi+repo&utm_medium=github+sponsorship" target="_blank" title="SDKs for your API | Speakeasy"><img src="https://fastapi.tiangolo.com/img/sponsors/speakeasy.png"></a>

8
docs/de/docs/advanced/async-tests.md

@ -60,9 +60,7 @@ $ pytest
Der Marker `@pytest.mark.anyio` teilt pytest mit, dass diese Testfunktion asynchron aufgerufen werden soll:
```Python hl_lines="7"
{!../../docs_src/async_tests/test_main.py!}
```
{* ../../docs_src/async_tests/test_main.py hl[7] *}
/// tip | "Tipp"
@ -72,9 +70,7 @@ Beachten Sie, dass die Testfunktion jetzt `async def` ist und nicht nur `def` wi
Dann können wir einen `AsyncClient` mit der App erstellen und mit `await` asynchrone Requests an ihn senden.
```Python hl_lines="9-12"
{!../../docs_src/async_tests/test_main.py!}
```
{* ../../docs_src/async_tests/test_main.py hl[9:12] *}
Das ist das Äquivalent zu:

91
docs/de/docs/advanced/security/http-basic-auth.md

@ -20,36 +20,7 @@ Wenn Sie dann den Benutzernamen und das Passwort eingeben, sendet der Browser di
* Diese gibt ein Objekt vom Typ `HTTPBasicCredentials` zurück:
* Es enthält den gesendeten `username` und das gesendete `password`.
//// tab | Python 3.9+
```Python hl_lines="4 8 12"
{!> ../../docs_src/security/tutorial006_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="2 7 11"
{!> ../../docs_src/security/tutorial006_an.py!}
```
////
//// tab | Python 3.8+ nicht annotiert
/// tip | "Tipp"
Bevorzugen Sie die `Annotated`-Version, falls möglich.
///
```Python hl_lines="2 6 10"
{!> ../../docs_src/security/tutorial006.py!}
```
////
{* ../../docs_src/security/tutorial006_an_py39.py hl[4,8,12] *}
Wenn 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:
<img src="/img/tutorial/security/image12.png">
@ -68,35 +39,7 @@ Um dies zu lösen, konvertieren wir zunächst den `username` und das `password`
Dann können wir `secrets.compare_digest()` verwenden, um sicherzustellen, dass `credentials.username` `"stanleyjobson"` und `credentials.password` `"swordfish"` ist.
//// tab | Python 3.9+
```Python hl_lines="1 12-24"
{!> ../../docs_src/security/tutorial007_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="1 12-24"
{!> ../../docs_src/security/tutorial007_an.py!}
```
////
//// tab | Python 3.8+ nicht annotiert
/// tip | "Tipp"
Bevorzugen Sie die `Annotated`-Version, falls möglich.
///
```Python hl_lines="1 11-21"
{!> ../../docs_src/security/tutorial007.py!}
```
////
{* ../../docs_src/security/tutorial007_an_py39.py hl[1,12:24] *}
Dies wäre das gleiche wie:
@ -160,32 +103,4 @@ So ist Ihr Anwendungscode, dank der Verwendung von `secrets.compare_digest()`, v
Nachdem 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:
//// tab | Python 3.9+
```Python hl_lines="26-30"
{!> ../../docs_src/security/tutorial007_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="26-30"
{!> ../../docs_src/security/tutorial007_an.py!}
```
////
//// tab | Python 3.8+ nicht annotiert
/// tip | "Tipp"
Bevorzugen Sie die `Annotated`-Version, falls möglich.
///
```Python hl_lines="23-27"
{!> ../../docs_src/security/tutorial007.py!}
```
////
{* ../../docs_src/security/tutorial007_an_py39.py hl[26:30] *}

12
docs/de/docs/tutorial/response-status-code.md

@ -8,9 +8,7 @@ So wie ein Responsemodell, können Sie auch einen HTTP-Statuscode für die Respo
* `@app.delete()`
* usw.
```Python hl_lines="6"
{!../../docs_src/response_status_code/tutorial001.py!}
```
{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
/// note | "Hinweis"
@ -76,9 +74,7 @@ Um mehr über Statuscodes zu lernen, und welcher wofür verwendet wird, lesen Si
Schauen wir uns das vorherige Beispiel noch einmal an:
```Python hl_lines="6"
{!../../docs_src/response_status_code/tutorial001.py!}
```
{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
`201` ist der Statuscode für „Created“ („Erzeugt“).
@ -86,9 +82,7 @@ Aber Sie müssen sich nicht daran erinnern, welcher dieser Codes was bedeutet.
Sie können die Hilfsvariablen von `fastapi.status` verwenden.
```Python hl_lines="1 6"
{!../../docs_src/response_status_code/tutorial002.py!}
```
{* ../../docs_src/response_status_code/tutorial002.py hl[1,6] *}
Diese sind nur eine Annehmlichkeit und enthalten dieselbe Nummer, aber auf diese Weise können Sie die Autovervollständigung Ihres Editors verwenden, um sie zu finden:

3
docs/en/data/sponsors.yml

@ -29,6 +29,9 @@ gold:
- url: https://liblab.com?utm_source=fastapi
title: liblab - Generate SDKs from FastAPI
img: https://fastapi.tiangolo.com/img/sponsors/liblab.png
- url: https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi
title: Deploy & scale any full-stack web app on Render. Focus on building apps, not infra.
img: https://fastapi.tiangolo.com/img/sponsors/render.svg
silver:
- url: https://github.com/deepset-ai/haystack/
title: Build powerful search from composable, open source building blocks

1
docs/en/data/sponsors_badge.yml

@ -31,3 +31,4 @@ logins:
- zuplo-oss
- Kong
- speakeasy-api
- jess-render

16
docs/en/docs/advanced/additional-responses.md

@ -26,9 +26,7 @@ Each of those response `dict`s can have a key `model`, containing a Pydantic mod
For example, to declare another response with a status code `404` and a Pydantic model `Message`, you can write:
```Python hl_lines="18 22"
{!../../docs_src/additional_responses/tutorial001.py!}
```
{* ../../docs_src/additional_responses/tutorial001.py hl[18,22] *}
/// note
@ -177,9 +175,7 @@ You can use this same `responses` parameter to add different media types for the
For 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:
```Python hl_lines="19-24 28"
{!../../docs_src/additional_responses/tutorial002.py!}
```
{* ../../docs_src/additional_responses/tutorial002.py hl[19:24,28] *}
/// note
@ -207,9 +203,7 @@ For example, you can declare a response with a status code `404` that uses a Pyd
And a response with a status code `200` that uses your `response_model`, but includes a custom `example`:
```Python hl_lines="20-31"
{!../../docs_src/additional_responses/tutorial003.py!}
```
{* ../../docs_src/additional_responses/tutorial003.py hl[20:31] *}
It will all be combined and included in your OpenAPI, and shown in the API docs:
@ -243,9 +237,7 @@ You can use that technique to reuse some predefined responses in your *path oper
For example:
```Python hl_lines="13-17 26"
{!../../docs_src/additional_responses/tutorial004.py!}
```
{* ../../docs_src/additional_responses/tutorial004.py hl[13:17,26] *}
## More information about OpenAPI responses

52
docs/en/docs/advanced/additional-status-codes.md

@ -14,57 +14,7 @@ But you also want it to accept new items. And when the items didn't exist before
To achieve that, import `JSONResponse`, and return your content there directly, setting the `status_code` that you want:
//// tab | Python 3.10+
```Python hl_lines="4 25"
{!> ../../docs_src/additional_status_codes/tutorial001_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="4 25"
{!> ../../docs_src/additional_status_codes/tutorial001_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="4 26"
{!> ../../docs_src/additional_status_codes/tutorial001_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="2 23"
{!> ../../docs_src/additional_status_codes/tutorial001_py310.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="4 25"
{!> ../../docs_src/additional_status_codes/tutorial001.py!}
```
////
{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
/// warning

120
docs/en/docs/advanced/advanced-dependencies.md

@ -18,35 +18,7 @@ Not the class itself (which is already a callable), but an instance of that clas
To do that, we declare a method `__call__`:
//// tab | Python 3.9+
```Python hl_lines="12"
{!> ../../docs_src/dependencies/tutorial011_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="11"
{!> ../../docs_src/dependencies/tutorial011_an.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="10"
{!> ../../docs_src/dependencies/tutorial011.py!}
```
////
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *}
In 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.
@ -54,35 +26,7 @@ In this case, this `__call__` is what **FastAPI** will use to check for addition
And now, we can use `__init__` to declare the parameters of the instance that we can use to "parameterize" the dependency:
//// tab | Python 3.9+
```Python hl_lines="9"
{!> ../../docs_src/dependencies/tutorial011_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="8"
{!> ../../docs_src/dependencies/tutorial011_an.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="7"
{!> ../../docs_src/dependencies/tutorial011.py!}
```
////
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[9] *}
In this case, **FastAPI** won't ever touch or care about `__init__`, we will use it directly in our code.
@ -90,35 +34,7 @@ In this case, **FastAPI** won't ever touch or care about `__init__`, we will use
We could create an instance of this class with:
//// tab | Python 3.9+
```Python hl_lines="18"
{!> ../../docs_src/dependencies/tutorial011_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="17"
{!> ../../docs_src/dependencies/tutorial011_an.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="16"
{!> ../../docs_src/dependencies/tutorial011.py!}
```
////
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[18] *}
And that way we are able to "parameterize" our dependency, that now has `"bar"` inside of it, as the attribute `checker.fixed_content`.
@ -134,35 +50,7 @@ checker(q="somequery")
...and pass whatever that returns as the value of the dependency in our *path operation function* as the parameter `fixed_content_included`:
//// tab | Python 3.9+
```Python hl_lines="22"
{!> ../../docs_src/dependencies/tutorial011_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="21"
{!> ../../docs_src/dependencies/tutorial011_an.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="20"
{!> ../../docs_src/dependencies/tutorial011.py!}
```
////
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *}
/// tip

16
docs/en/docs/advanced/async-tests.md

@ -32,15 +32,11 @@ For a simple example, let's consider a file structure similar to the one describ
The file `main.py` would have:
```Python
{!../../docs_src/async_tests/main.py!}
```
{* ../../docs_src/async_tests/main.py *}
The file `test_main.py` would have the tests for `main.py`, it could look like this now:
```Python
{!../../docs_src/async_tests/test_main.py!}
```
{* ../../docs_src/async_tests/test_main.py *}
## Run it
@ -60,9 +56,7 @@ $ pytest
The marker `@pytest.mark.anyio` tells pytest that this test function should be called asynchronously:
```Python hl_lines="7"
{!../../docs_src/async_tests/test_main.py!}
```
{* ../../docs_src/async_tests/test_main.py hl[7] *}
/// tip
@ -72,9 +66,7 @@ Note that the test function is now `async def` instead of just `def` as before w
Then we can create an `AsyncClient` with the app, and send async requests to it, using `await`.
```Python hl_lines="9-12"
{!../../docs_src/async_tests/test_main.py!}
```
{* ../../docs_src/async_tests/test_main.py hl[9:12] *}
This is the equivalent to:

20
docs/en/docs/advanced/behind-a-proxy.md

@ -18,9 +18,7 @@ In this case, the original path `/app` would actually be served at `/api/v1/app`
Even though all your code is written assuming there's just `/app`.
```Python hl_lines="6"
{!../../docs_src/behind_a_proxy/tutorial001.py!}
```
{* ../../docs_src/behind_a_proxy/tutorial001.py hl[6] *}
And 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`.
@ -98,9 +96,7 @@ You can get the current `root_path` used by your application for each request, i
Here we are including it in the message just for demonstration purposes.
```Python hl_lines="8"
{!../../docs_src/behind_a_proxy/tutorial001.py!}
```
{* ../../docs_src/behind_a_proxy/tutorial001.py hl[8] *}
Then, if you start Uvicorn with:
@ -127,9 +123,7 @@ The response would be something like:
Alternatively, 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:
```Python hl_lines="3"
{!../../docs_src/behind_a_proxy/tutorial002.py!}
```
{* ../../docs_src/behind_a_proxy/tutorial002.py hl[3] *}
Passing the `root_path` to `FastAPI` would be the equivalent of passing the `--root-path` command line option to Uvicorn or Hypercorn.
@ -309,9 +303,7 @@ If you pass a custom list of `servers` and there's a `root_path` (because your A
For example:
```Python hl_lines="4-7"
{!../../docs_src/behind_a_proxy/tutorial003.py!}
```
{* ../../docs_src/behind_a_proxy/tutorial003.py hl[4:7] *}
Will generate an OpenAPI schema like:
@ -358,9 +350,7 @@ The docs UI will interact with the server that you select.
If you don't want **FastAPI** to include an automatic server using the `root_path`, you can use the parameter `root_path_in_servers=False`:
```Python hl_lines="9"
{!../../docs_src/behind_a_proxy/tutorial004.py!}
```
{* ../../docs_src/behind_a_proxy/tutorial004.py hl[9] *}
and then it won't include it in the OpenAPI schema.

12
docs/en/docs/advanced/dataclasses.md

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

24
docs/en/docs/advanced/events.md

@ -30,9 +30,7 @@ Let's start with an example and then see it in detail.
We create an async function `lifespan()` with `yield` like this:
```Python hl_lines="16 19"
{!../../docs_src/events/tutorial003.py!}
```
{* ../../docs_src/events/tutorial003.py hl[16,19] *}
Here 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*.
@ -50,9 +48,7 @@ Maybe you need to start a new version, or you just got tired of running it. 🤷
The first thing to notice, is that we are defining an async function with `yield`. This is very similar to Dependencies with `yield`.
```Python hl_lines="14-19"
{!../../docs_src/events/tutorial003.py!}
```
{* ../../docs_src/events/tutorial003.py hl[14:19] *}
The first part of the function, before the `yield`, will be executed **before** the application starts.
@ -64,9 +60,7 @@ If you check, the function is decorated with an `@asynccontextmanager`.
That converts the function into something called an "**async context manager**".
```Python hl_lines="1 13"
{!../../docs_src/events/tutorial003.py!}
```
{* ../../docs_src/events/tutorial003.py hl[1,13] *}
A **context manager** in Python is something that you can use in a `with` statement, for example, `open()` can be used as a context manager:
@ -88,9 +82,7 @@ In our code example above, we don't use it directly, but we pass it to FastAPI f
The `lifespan` parameter of the `FastAPI` app takes an **async context manager**, so we can pass our new `lifespan` async context manager to it.
```Python hl_lines="22"
{!../../docs_src/events/tutorial003.py!}
```
{* ../../docs_src/events/tutorial003.py hl[22] *}
## Alternative Events (deprecated)
@ -112,9 +104,7 @@ These functions can be declared with `async def` or normal `def`.
To add a function that should be run before the application starts, declare it with the event `"startup"`:
```Python hl_lines="8"
{!../../docs_src/events/tutorial001.py!}
```
{* ../../docs_src/events/tutorial001.py hl[8] *}
In this case, the `startup` event handler function will initialize the items "database" (just a `dict`) with some values.
@ -126,9 +116,7 @@ And your application won't start receiving requests until all the `startup` even
To add a function that should be run when the application is shutting down, declare it with the event `"shutdown"`:
```Python hl_lines="6"
{!../../docs_src/events/tutorial002.py!}
```
{* ../../docs_src/events/tutorial002.py hl[6] *}
Here, the `shutdown` event handler function will write a text line `"Application shutdown"` to a file `log.txt`.

12
docs/en/docs/advanced/middleware.md

@ -57,17 +57,13 @@ Enforces that all incoming requests must either be `https` or `wss`.
Any incoming request to `http` or `ws` will be redirected to the secure scheme instead.
```Python hl_lines="2 6"
{!../../docs_src/advanced_middleware/tutorial001.py!}
```
{* ../../docs_src/advanced_middleware/tutorial001.py hl[2,6] *}
## `TrustedHostMiddleware`
Enforces that all incoming requests have a correctly set `Host` header, in order to guard against HTTP Host Header attacks.
```Python hl_lines="2 6-8"
{!../../docs_src/advanced_middleware/tutorial002.py!}
```
{* ../../docs_src/advanced_middleware/tutorial002.py hl[2,6:8] *}
The following arguments are supported:
@ -81,9 +77,7 @@ Handles GZip responses for any request that includes `"gzip"` in the `Accept-Enc
The middleware will handle both standard and streaming responses.
```Python hl_lines="2 6"
{!../../docs_src/advanced_middleware/tutorial003.py!}
```
{* ../../docs_src/advanced_middleware/tutorial003.py hl[2,6] *}
The following arguments are supported:

4
docs/en/docs/advanced/openapi-webhooks.md

@ -32,9 +32,7 @@ Webhooks are available in OpenAPI 3.1.0 and above, supported by FastAPI `0.99.0`
When 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()`.
```Python hl_lines="9-13 36-53"
{!../../docs_src/openapi_webhooks/tutorial001.py!}
```
{* ../../docs_src/openapi_webhooks/tutorial001.py hl[9:13,36:53] *}
The webhooks that you define will end up in the **OpenAPI** schema and the automatic **docs UI**.

90
docs/en/docs/advanced/security/http-basic-auth.md

@ -20,35 +20,7 @@ Then, when you type that username and password, the browser sends them in the he
* It returns an object of type `HTTPBasicCredentials`:
* It contains the `username` and `password` sent.
//// tab | Python 3.9+
```Python hl_lines="4 8 12"
{!> ../../docs_src/security/tutorial006_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="2 7 11"
{!> ../../docs_src/security/tutorial006_an.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="2 6 10"
{!> ../../docs_src/security/tutorial006.py!}
```
////
{* ../../docs_src/security/tutorial006_an_py39.py hl[4,8,12] *}
When 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:
@ -68,35 +40,7 @@ To handle that, we first convert the `username` and `password` to `bytes` encodi
Then we can use `secrets.compare_digest()` to ensure that `credentials.username` is `"stanleyjobson"`, and that `credentials.password` is `"swordfish"`.
//// tab | Python 3.9+
```Python hl_lines="1 12-24"
{!> ../../docs_src/security/tutorial007_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="1 12-24"
{!> ../../docs_src/security/tutorial007_an.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="1 11-21"
{!> ../../docs_src/security/tutorial007.py!}
```
////
{* ../../docs_src/security/tutorial007_an_py39.py hl[1,12:24] *}
This would be similar to:
@ -160,32 +104,4 @@ That way, using `secrets.compare_digest()` in your application code, it will be
After 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:
//// tab | Python 3.9+
```Python hl_lines="26-30"
{!> ../../docs_src/security/tutorial007_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="26-30"
{!> ../../docs_src/security/tutorial007_an.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="23-27"
{!> ../../docs_src/security/tutorial007.py!}
```
////
{* ../../docs_src/security/tutorial007_an_py39.py hl[26:30] *}

528
docs/en/docs/advanced/security/oauth2-scopes.md

@ -62,71 +62,7 @@ For OAuth2 they are just strings.
First, 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){.internal-link target=_blank}. Now using OAuth2 scopes:
//// tab | Python 3.10+
```Python hl_lines="5 9 13 47 65 106 108-116 122-125 129-135 140 156"
{!> ../../docs_src/security/tutorial005_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="2 5 9 13 47 65 106 108-116 122-125 129-135 140 156"
{!> ../../docs_src/security/tutorial005_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="2 5 9 13 48 66 107 109-117 123-126 130-136 141 157"
{!> ../../docs_src/security/tutorial005_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="4 8 12 46 64 105 107-115 121-124 128-134 139 155"
{!> ../../docs_src/security/tutorial005_py310.py!}
```
////
//// tab | Python 3.9+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="2 5 9 13 47 65 106 108-116 122-125 129-135 140 156"
{!> ../../docs_src/security/tutorial005_py39.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="2 5 9 13 47 65 106 108-116 122-125 129-135 140 156"
{!> ../../docs_src/security/tutorial005.py!}
```
////
{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:125,129:135,140,156] *}
Now let's review those changes step by step.
@ -136,71 +72,7 @@ The first change is that now we are declaring the OAuth2 security scheme with tw
The `scopes` parameter receives a `dict` with each scope as a key and the description as the value:
//// tab | Python 3.10+
```Python hl_lines="63-66"
{!> ../../docs_src/security/tutorial005_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="63-66"
{!> ../../docs_src/security/tutorial005_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="64-67"
{!> ../../docs_src/security/tutorial005_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="62-65"
{!> ../../docs_src/security/tutorial005_py310.py!}
```
////
//// tab | Python 3.9+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="63-66"
{!> ../../docs_src/security/tutorial005_py39.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="63-66"
{!> ../../docs_src/security/tutorial005.py!}
```
////
{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}
Because we are now declaring those scopes, they will show up in the API docs when you log-in/authorize.
@ -226,71 +98,7 @@ But in your application, for security, you should make sure you only add the sco
///
//// tab | Python 3.10+
```Python hl_lines="156"
{!> ../../docs_src/security/tutorial005_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="156"
{!> ../../docs_src/security/tutorial005_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="157"
{!> ../../docs_src/security/tutorial005_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="155"
{!> ../../docs_src/security/tutorial005_py310.py!}
```
////
//// tab | Python 3.9+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="156"
{!> ../../docs_src/security/tutorial005_py39.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="156"
{!> ../../docs_src/security/tutorial005.py!}
```
////
{* ../../docs_src/security/tutorial005_an_py310.py hl[156] *}
## Declare scopes in *path operations* and dependencies
@ -316,71 +124,7 @@ We are doing it here to demonstrate how **FastAPI** handles scopes declared at d
///
//// tab | Python 3.10+
```Python hl_lines="5 140 171"
{!> ../../docs_src/security/tutorial005_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="5 140 171"
{!> ../../docs_src/security/tutorial005_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="5 141 172"
{!> ../../docs_src/security/tutorial005_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="4 139 168"
{!> ../../docs_src/security/tutorial005_py310.py!}
```
////
//// tab | Python 3.9+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="5 140 169"
{!> ../../docs_src/security/tutorial005_py39.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="5 140 169"
{!> ../../docs_src/security/tutorial005.py!}
```
////
{* ../../docs_src/security/tutorial005_an_py310.py hl[5,140,171] *}
/// info | "Technical Details"
@ -406,71 +150,7 @@ We also declare a special parameter of type `SecurityScopes`, imported from `fas
This `SecurityScopes` class is similar to `Request` (`Request` was used to get the request object directly).
//// tab | Python 3.10+
```Python hl_lines="9 106"
{!> ../../docs_src/security/tutorial005_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="9 106"
{!> ../../docs_src/security/tutorial005_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="9 107"
{!> ../../docs_src/security/tutorial005_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="8 105"
{!> ../../docs_src/security/tutorial005_py310.py!}
```
////
//// tab | Python 3.9+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="9 106"
{!> ../../docs_src/security/tutorial005_py39.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="9 106"
{!> ../../docs_src/security/tutorial005.py!}
```
////
{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}
## Use the `scopes`
@ -484,71 +164,7 @@ We create an `HTTPException` that we can reuse (`raise`) later at several points
In 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).
//// tab | Python 3.10+
```Python hl_lines="106 108-116"
{!> ../../docs_src/security/tutorial005_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="106 108-116"
{!> ../../docs_src/security/tutorial005_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="107 109-117"
{!> ../../docs_src/security/tutorial005_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="105 107-115"
{!> ../../docs_src/security/tutorial005_py310.py!}
```
////
//// tab | Python 3.9+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="106 108-116"
{!> ../../docs_src/security/tutorial005_py39.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="106 108-116"
{!> ../../docs_src/security/tutorial005.py!}
```
////
{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}
## Verify the `username` and data shape
@ -564,71 +180,7 @@ Instead of, for example, a `dict`, or something else, as it could break the appl
We also verify that we have a user with that username, and if not, we raise that same exception we created before.
//// tab | Python 3.10+
```Python hl_lines="47 117-128"
{!> ../../docs_src/security/tutorial005_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="47 117-128"
{!> ../../docs_src/security/tutorial005_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="48 118-129"
{!> ../../docs_src/security/tutorial005_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="46 116-127"
{!> ../../docs_src/security/tutorial005_py310.py!}
```
////
//// tab | Python 3.9+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="47 117-128"
{!> ../../docs_src/security/tutorial005_py39.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="47 117-128"
{!> ../../docs_src/security/tutorial005.py!}
```
////
{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:128] *}
## Verify the `scopes`
@ -636,71 +188,7 @@ We now verify that all the scopes required, by this dependency and all the depen
For this, we use `security_scopes.scopes`, that contains a `list` with all these scopes as `str`.
//// tab | Python 3.10+
```Python hl_lines="129-135"
{!> ../../docs_src/security/tutorial005_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="129-135"
{!> ../../docs_src/security/tutorial005_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="130-136"
{!> ../../docs_src/security/tutorial005_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="128-134"
{!> ../../docs_src/security/tutorial005_py310.py!}
```
////
//// tab | Python 3.9+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="129-135"
{!> ../../docs_src/security/tutorial005_py39.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="129-135"
{!> ../../docs_src/security/tutorial005.py!}
```
////
{* ../../docs_src/security/tutorial005_an_py310.py hl[129:135] *}
## Dependency tree and scopes

1
docs/en/docs/deployment/cloud.md

@ -15,3 +15,4 @@ You might want to try their services and follow their guides:
* <a href="https://docs.platform.sh/languages/python.html?utm_source=fastapi-signup&utm_medium=banner&utm_campaign=FastAPI-signup-June-2023" class="external-link" target="_blank">Platform.sh</a>
* <a href="https://docs.porter.run/language-specific-guides/fastapi" class="external-link" target="_blank">Porter</a>
* <a href="https://www.withcoherence.com/?utm_medium=advertising&utm_source=fastapi&utm_campaign=website" class="external-link" target="_blank">Coherence</a>
* <a href="https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi" class="external-link" target="_blank">Render</a>

4
docs/en/docs/how-to/conditional-openapi.md

@ -29,9 +29,7 @@ You can easily use the same Pydantic settings to configure your generated OpenAP
For example:
```Python hl_lines="6 11"
{!../../docs_src/conditional_openapi/tutorial001.py!}
```
{* ../../docs_src/conditional_openapi/tutorial001.py hl[6,11] *}
Here we declare the setting `openapi_url` with the same default of `"/openapi.json"`.

16
docs/en/docs/how-to/configure-swagger-ui.md

@ -18,9 +18,7 @@ Without changing the settings, syntax highlighting is enabled by default:
But you can disable it by setting `syntaxHighlight` to `False`:
```Python hl_lines="3"
{!../../docs_src/configure_swagger_ui/tutorial001.py!}
```
{* ../../docs_src/configure_swagger_ui/tutorial001.py hl[3] *}
...and then Swagger UI won't show the syntax highlighting anymore:
@ -30,9 +28,7 @@ But you can disable it by setting `syntaxHighlight` to `False`:
The same way you could set the syntax highlighting theme with the key `"syntaxHighlight.theme"` (notice that it has a dot in the middle):
```Python hl_lines="3"
{!../../docs_src/configure_swagger_ui/tutorial002.py!}
```
{* ../../docs_src/configure_swagger_ui/tutorial002.py hl[3] *}
That configuration would change the syntax highlighting color theme:
@ -44,17 +40,13 @@ FastAPI includes some default configuration parameters appropriate for most of t
It includes these default configurations:
```Python
{!../../fastapi/openapi/docs.py[ln:7-23]!}
```
{* ../../fastapi/openapi/docs.py ln[8:23] hl[17:23] *}
You can override any of them by setting a different value in the argument `swagger_ui_parameters`.
For example, to disable `deepLinking` you could pass these settings to `swagger_ui_parameters`:
```Python hl_lines="3"
{!../../docs_src/configure_swagger_ui/tutorial003.py!}
```
{* ../../docs_src/configure_swagger_ui/tutorial003.py hl[3] *}
## Other Swagger UI Parameters

28
docs/en/docs/how-to/custom-docs-ui-assets.md

@ -18,9 +18,7 @@ The first step is to disable the automatic docs, as by default, those use the de
To disable them, set their URLs to `None` when creating your `FastAPI` app:
```Python hl_lines="8"
{!../../docs_src/custom_docs_ui/tutorial001.py!}
```
{* ../../docs_src/custom_docs_ui/tutorial001.py hl[8] *}
### Include the custom docs
@ -36,9 +34,7 @@ You can reuse FastAPI's internal functions to create the HTML pages for the docs
And similarly for ReDoc...
```Python hl_lines="2-6 11-19 22-24 27-33"
{!../../docs_src/custom_docs_ui/tutorial001.py!}
```
{* ../../docs_src/custom_docs_ui/tutorial001.py hl[2:6,11:19,22:24,27:33] *}
/// tip
@ -54,9 +50,7 @@ Swagger UI will handle it behind the scenes for you, but it needs this "redirect
Now, to be able to test that everything works, create a *path operation*:
```Python hl_lines="36-38"
{!../../docs_src/custom_docs_ui/tutorial001.py!}
```
{* ../../docs_src/custom_docs_ui/tutorial001.py hl[36:38] *}
### Test it
@ -124,9 +118,7 @@ After that, your file structure could look like:
* Import `StaticFiles`.
* "Mount" a `StaticFiles()` instance in a specific path.
```Python hl_lines="7 11"
{!../../docs_src/custom_docs_ui/tutorial002.py!}
```
{* ../../docs_src/custom_docs_ui/tutorial002.py hl[7,11] *}
### Test the static files
@ -158,9 +150,7 @@ The same as when using a custom CDN, the first step is to disable the automatic
To disable them, set their URLs to `None` when creating your `FastAPI` app:
```Python hl_lines="9"
{!../../docs_src/custom_docs_ui/tutorial002.py!}
```
{* ../../docs_src/custom_docs_ui/tutorial002.py hl[9] *}
### Include the custom docs for static files
@ -176,9 +166,7 @@ Again, you can reuse FastAPI's internal functions to create the HTML pages for t
And similarly for ReDoc...
```Python hl_lines="2-6 14-22 25-27 30-36"
{!../../docs_src/custom_docs_ui/tutorial002.py!}
```
{* ../../docs_src/custom_docs_ui/tutorial002.py hl[2:6,14:22,25:27,30:36] *}
/// tip
@ -194,9 +182,7 @@ Swagger UI will handle it behind the scenes for you, but it needs this "redirect
Now, to be able to test that everything works, create a *path operation*:
```Python hl_lines="39-41"
{!../../docs_src/custom_docs_ui/tutorial002.py!}
```
{* ../../docs_src/custom_docs_ui/tutorial002.py hl[39:41] *}
### Test Static Files UI

24
docs/en/docs/how-to/custom-request-and-route.md

@ -42,9 +42,7 @@ If there's no `gzip` in the header, it will not try to decompress the body.
That way, the same route class can handle gzip compressed or uncompressed requests.
```Python hl_lines="8-15"
{!../../docs_src/custom_request_and_route/tutorial001.py!}
```
{* ../../docs_src/custom_request_and_route/tutorial001.py hl[8:15] *}
### Create a custom `GzipRoute` class
@ -56,9 +54,7 @@ This method returns a function. And that function is what will receive a request
Here we use it to create a `GzipRequest` from the original request.
```Python hl_lines="18-26"
{!../../docs_src/custom_request_and_route/tutorial001.py!}
```
{* ../../docs_src/custom_request_and_route/tutorial001.py hl[18:26] *}
/// note | "Technical Details"
@ -96,26 +92,18 @@ We can also use this same approach to access the request body in an exception ha
All we need to do is handle the request inside a `try`/`except` block:
```Python hl_lines="13 15"
{!../../docs_src/custom_request_and_route/tutorial002.py!}
```
{* ../../docs_src/custom_request_and_route/tutorial002.py hl[13,15] *}
If 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:
```Python hl_lines="16-18"
{!../../docs_src/custom_request_and_route/tutorial002.py!}
```
{* ../../docs_src/custom_request_and_route/tutorial002.py hl[16:18] *}
## Custom `APIRoute` class in a router
You can also set the `route_class` parameter of an `APIRouter`:
```Python hl_lines="26"
{!../../docs_src/custom_request_and_route/tutorial003.py!}
```
{* ../../docs_src/custom_request_and_route/tutorial003.py hl[26] *}
In 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:
```Python hl_lines="13-20"
{!../../docs_src/custom_request_and_route/tutorial003.py!}
```
{* ../../docs_src/custom_request_and_route/tutorial003.py hl[13:20] *}

20
docs/en/docs/how-to/extending-openapi.md

@ -43,25 +43,19 @@ For example, let's add <a href="https://github.com/Rebilly/ReDoc/blob/master/doc
First, write all your **FastAPI** application as normally:
```Python hl_lines="1 4 7-9"
{!../../docs_src/extending_openapi/tutorial001.py!}
```
{* ../../docs_src/extending_openapi/tutorial001.py hl[1,4,7:9] *}
### Generate the OpenAPI schema
Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function:
```Python hl_lines="2 15-21"
{!../../docs_src/extending_openapi/tutorial001.py!}
```
{* ../../docs_src/extending_openapi/tutorial001.py hl[2,15:21] *}
### Modify the OpenAPI schema
Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema:
```Python hl_lines="22-24"
{!../../docs_src/extending_openapi/tutorial001.py!}
```
{* ../../docs_src/extending_openapi/tutorial001.py hl[22:24] *}
### Cache the OpenAPI schema
@ -71,17 +65,13 @@ That way, your application won't have to generate the schema every time a user o
It will be generated only once, and then the same cached schema will be used for the next requests.
```Python hl_lines="13-14 25-26"
{!../../docs_src/extending_openapi/tutorial001.py!}
```
{* ../../docs_src/extending_openapi/tutorial001.py hl[13:14,25:26] *}
### Override the method
Now you can replace the `.openapi()` method with your new function.
```Python hl_lines="29"
{!../../docs_src/extending_openapi/tutorial001.py!}
```
{* ../../docs_src/extending_openapi/tutorial001.py hl[29] *}
### Check it

4
docs/en/docs/how-to/graphql.md

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

162
docs/en/docs/how-to/separate-openapi-schemas.md

@ -10,123 +10,13 @@ Let's see how that works and how to change it if you need to do that.
Let's say you have a Pydantic model with default values, like this one:
//// tab | Python 3.10+
```Python hl_lines="7"
{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py[ln:1-7]!}
# Code below omitted 👇
```
<details>
<summary>👀 Full file preview</summary>
```Python
{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py!}
```
</details>
////
//// tab | Python 3.9+
```Python hl_lines="9"
{!> ../../docs_src/separate_openapi_schemas/tutorial001_py39.py[ln:1-9]!}
# Code below omitted 👇
```
<details>
<summary>👀 Full file preview</summary>
```Python
{!> ../../docs_src/separate_openapi_schemas/tutorial001_py39.py!}
```
</details>
////
//// tab | Python 3.8+
```Python hl_lines="9"
{!> ../../docs_src/separate_openapi_schemas/tutorial001.py[ln:1-9]!}
# Code below omitted 👇
```
<details>
<summary>👀 Full file preview</summary>
```Python
{!> ../../docs_src/separate_openapi_schemas/tutorial001.py!}
```
</details>
////
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}
### Model for Input
If you use this model as an input like here:
//// tab | Python 3.10+
```Python hl_lines="14"
{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py[ln:1-15]!}
# Code below omitted 👇
```
<details>
<summary>👀 Full file preview</summary>
```Python
{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py!}
```
</details>
////
//// tab | Python 3.9+
```Python hl_lines="16"
{!> ../../docs_src/separate_openapi_schemas/tutorial001_py39.py[ln:1-17]!}
# Code below omitted 👇
```
<details>
<summary>👀 Full file preview</summary>
```Python
{!> ../../docs_src/separate_openapi_schemas/tutorial001_py39.py!}
```
</details>
////
//// tab | Python 3.8+
```Python hl_lines="16"
{!> ../../docs_src/separate_openapi_schemas/tutorial001.py[ln:1-17]!}
# Code below omitted 👇
```
<details>
<summary>👀 Full file preview</summary>
```Python
{!> ../../docs_src/separate_openapi_schemas/tutorial001.py!}
```
</details>
////
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}
...then the `description` field will **not be required**. Because it has a default value of `None`.
@ -142,29 +32,7 @@ You can confirm that in the docs, the `description` field doesn't have a **red a
But if you use the same model as an output, like here:
//// tab | Python 3.10+
```Python hl_lines="19"
{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="21"
{!> ../../docs_src/separate_openapi_schemas/tutorial001_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="21"
{!> ../../docs_src/separate_openapi_schemas/tutorial001.py!}
```
////
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}
...then because `description` has a default value, if you **don't return anything** for that field, it will still have that **default value**.
@ -223,29 +91,7 @@ Support for `separate_input_output_schemas` was added in FastAPI `0.102.0`. 🤓
///
//// tab | Python 3.10+
```Python hl_lines="10"
{!> ../../docs_src/separate_openapi_schemas/tutorial002_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="12"
{!> ../../docs_src/separate_openapi_schemas/tutorial002_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="12"
{!> ../../docs_src/separate_openapi_schemas/tutorial002.py!}
```
////
{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}
### Same Schema for Input and Output Models in Docs

25
docs/en/docs/img/sponsors/render-banner.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

24
docs/en/docs/img/sponsors/render.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

40
docs/en/docs/python-types.md

@ -22,9 +22,7 @@ If you are a Python expert, and you already know everything about type hints, sk
Let's start with a simple example:
```Python
{!../../docs_src/python_types/tutorial001.py!}
```
{* ../../docs_src/python_types/tutorial001.py *}
Calling this program outputs:
@ -38,9 +36,7 @@ The function does the following:
* Converts the first letter of each one to upper case with `title()`.
* <abbr title="Puts them together, as one. With the contents of one after the other.">Concatenates</abbr> them with a space in the middle.
```Python hl_lines="2"
{!../../docs_src/python_types/tutorial001.py!}
```
{* ../../docs_src/python_types/tutorial001.py hl[2] *}
### Edit it
@ -82,9 +78,7 @@ That's it.
Those are the "type hints":
```Python hl_lines="1"
{!../../docs_src/python_types/tutorial002.py!}
```
{* ../../docs_src/python_types/tutorial002.py hl[1] *}
That is not the same as declaring default values like would be with:
@ -112,9 +106,7 @@ With that, you can scroll, seeing the options, until you find the one that "ring
Check this function, it already has type hints:
```Python hl_lines="1"
{!../../docs_src/python_types/tutorial003.py!}
```
{* ../../docs_src/python_types/tutorial003.py hl[1] *}
Because the editor knows the types of the variables, you don't only get completion, you also get error checks:
@ -122,9 +114,7 @@ Because the editor knows the types of the variables, you don't only get completi
Now you know that you have to fix it, convert `age` to a string with `str(age)`:
```Python hl_lines="2"
{!../../docs_src/python_types/tutorial004.py!}
```
{* ../../docs_src/python_types/tutorial004.py hl[2] *}
## Declaring types
@ -143,9 +133,7 @@ You can use, for example:
* `bool`
* `bytes`
```Python hl_lines="1"
{!../../docs_src/python_types/tutorial005.py!}
```
{* ../../docs_src/python_types/tutorial005.py hl[1] *}
### Generic types with type parameters
@ -369,9 +357,7 @@ It's just about the words and names. But those words can affect how you and your
As an example, let's take this function:
```Python hl_lines="1 4"
{!../../docs_src/python_types/tutorial009c.py!}
```
{* ../../docs_src/python_types/tutorial009c.py hl[1,4] *}
The parameter `name` is defined as `Optional[str]`, but it is **not optional**, you cannot call the function without the parameter:
@ -387,9 +373,7 @@ say_hi(name=None) # This works, None is valid 🎉
The good news is, once you are on Python 3.10 you won't have to worry about that, as you will be able to simply use `|` to define unions of types:
```Python hl_lines="1 4"
{!../../docs_src/python_types/tutorial009c_py310.py!}
```
{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
And then you won't have to worry about names like `Optional` and `Union`. 😎
@ -451,15 +435,11 @@ You can also declare a class as the type of a variable.
Let's say you have a class `Person`, with a name:
```Python hl_lines="1-3"
{!../../docs_src/python_types/tutorial010.py!}
```
{* ../../docs_src/python_types/tutorial010.py hl[1:3] *}
Then you can declare a variable to be of type `Person`:
```Python hl_lines="6"
{!../../docs_src/python_types/tutorial010.py!}
```
{* ../../docs_src/python_types/tutorial010.py hl[6] *}
And then, again, you get all the editor support:

82
docs/en/docs/release-notes.md

@ -9,12 +9,93 @@ hide:
### Docs
* 📝 Update includes in `docs/en/docs/advanced/security/oauth2-scopes.md`. PR [#12572](https://github.com/fastapi/fastapi/pull/12572) by [@krishnamadhavan](https://github.com/krishnamadhavan).
* 📝 Update includes for `docs/en/docs/how-to/conditional-openapi.md`. PR [#12624](https://github.com/fastapi/fastapi/pull/12624) by [@rabinlamadong](https://github.com/rabinlamadong).
* 📝 Update includes in `docs/en/docs/tutorial/dependencies/index.md`. PR [#12615](https://github.com/fastapi/fastapi/pull/12615) by [@bharara](https://github.com/bharara).
* 📝 Update includes in `docs/en/docs/tutorial/response-status-code.md`. PR [#12620](https://github.com/fastapi/fastapi/pull/12620) by [@kantandane](https://github.com/kantandane).
* 📝 Update includes in `docs/en/docs/how-to/custom-docs-ui-assets.md`. PR [#12623](https://github.com/fastapi/fastapi/pull/12623) by [@rabinlamadong](https://github.com/rabinlamadong).
* 📝 Update includes in `docs/en/docs/advanced/openapi-webhooks.md`. PR [#12605](https://github.com/fastapi/fastapi/pull/12605) by [@salmantec](https://github.com/salmantec).
* 📝 Update includes in `docs/en/docs/advanced/events.md`. PR [#12604](https://github.com/fastapi/fastapi/pull/12604) by [@salmantec](https://github.com/salmantec).
* 📝 Update includes in `docs/en/docs/advanced/dataclasses.md`. PR [#12603](https://github.com/fastapi/fastapi/pull/12603) by [@salmantec](https://github.com/salmantec).
* 📝 Update includes in `docs/es/docs/tutorial/cookie-params.md`. PR [#12602](https://github.com/fastapi/fastapi/pull/12602) by [@antonyare93](https://github.com/antonyare93).
* 📝 Update includes in `docs/fr/docs/tutorial/path-params-numeric-validations.md`. PR [#12601](https://github.com/fastapi/fastapi/pull/12601) by [@kantandane](https://github.com/kantandane).
* 📝 Update includes in `docs/fr/docs/tutorial/background-tasks.md`. PR [#12600](https://github.com/fastapi/fastapi/pull/12600) by [@kantandane](https://github.com/kantandane).
* 📝 Update includes in `docs/en/docs/tutorial/encoder.md`. PR [#12597](https://github.com/fastapi/fastapi/pull/12597) by [@tonyjly](https://github.com/tonyjly).
* 📝 Update includes in `docs/en/docs/how-to/custom-docs-ui-assets.md`. PR [#12557](https://github.com/fastapi/fastapi/pull/12557) by [@philipokiokio](https://github.com/philipokiokio).
* 🎨 Adjust spacing. PR [#12635](https://github.com/fastapi/fastapi/pull/12635) by [@alejsdev](https://github.com/alejsdev).
* 📝 Update includes in `docs/en/docs/how-to/custom-request-and-route.md`. PR [#12560](https://github.com/fastapi/fastapi/pull/12560) by [@philipokiokio](https://github.com/philipokiokio).
### Translations
* 🌐 Add Korean translation for `docs/ko/docs/advanced/wsgi.md`. PR [#12659](https://github.com/fastapi/fastapi/pull/12659) by [@Limsunoh](https://github.com/Limsunoh).
* 🌐 Add Portuguese translation for `docs/pt/docs/advanced/websockets.md`. PR [#12703](https://github.com/fastapi/fastapi/pull/12703) by [@devfernandoa](https://github.com/devfernandoa).
* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/security/simple-oauth2.md`. PR [#12520](https://github.com/fastapi/fastapi/pull/12520) by [@LidiaDomingos](https://github.com/LidiaDomingos).
* 🌐 Add Korean translation for `docs/ko/docs/advanced/response-directly.md`. PR [#12674](https://github.com/fastapi/fastapi/pull/12674) by [@9zimin9](https://github.com/9zimin9).
* 🌐 Add Portuguese translation for `docs/pt/docs/advanced/middleware.md`. PR [#12704](https://github.com/fastapi/fastapi/pull/12704) by [@devluisrodrigues](https://github.com/devluisrodrigues).
* 🌐 Add Portuguese translation for `docs/pt/docs/advanced/openapi-callbacks.md`. PR [#12705](https://github.com/fastapi/fastapi/pull/12705) by [@devfernandoa](https://github.com/devfernandoa).
* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/request-files.md`. PR [#12706](https://github.com/fastapi/fastapi/pull/12706) by [@devluisrodrigues](https://github.com/devluisrodrigues).
* 🌐 Add Portuguese Translation for `docs/pt/docs/advanced/custom-response.md`. PR [#12631](https://github.com/fastapi/fastapi/pull/12631) by [@Joao-Pedro-P-Holanda](https://github.com/Joao-Pedro-P-Holanda).
* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/metadata.md`. PR [#12538](https://github.com/fastapi/fastapi/pull/12538) by [@LinkolnR](https://github.com/LinkolnR).
* 🌐 Add Korean translation for `docs/ko/docs/tutorial/metadata.md`. PR [#12541](https://github.com/fastapi/fastapi/pull/12541) by [@kwang1215](https://github.com/kwang1215).
* 🌐 Add Korean Translation for `docs/ko/docs/advanced/response-cookies.md`. PR [#12546](https://github.com/fastapi/fastapi/pull/12546) by [@kim-sangah](https://github.com/kim-sangah).
* 🌐 Add Korean translation for `docs/ko/docs/fastapi-cli.md`. PR [#12515](https://github.com/fastapi/fastapi/pull/12515) by [@dhdld](https://github.com/dhdld).
* 🌐 Add Korean Translation for `docs/ko/docs/advanced/response-change-status-code.md`. PR [#12547](https://github.com/fastapi/fastapi/pull/12547) by [@9zimin9](https://github.com/9zimin9).
### Internal
* ⬆ Bump pypa/gh-action-pypi-publish from 1.10.3 to 1.11.0. PR [#12721](https://github.com/fastapi/fastapi/pull/12721) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Update pre-commit requirement from <4.0.0,>=2.17.0 to >=2.17.0,<5.0.0. PR [#12749](https://github.com/fastapi/fastapi/pull/12749) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump typer from 0.12.3 to 0.12.5. PR [#12748](https://github.com/fastapi/fastapi/pull/12748) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Update flask requirement from <3.0.0,>=1.1.2 to >=1.1.2,<4.0.0. PR [#12747](https://github.com/fastapi/fastapi/pull/12747) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump pillow from 10.4.0 to 11.0.0. PR [#12746](https://github.com/fastapi/fastapi/pull/12746) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Update pytest requirement from <8.0.0,>=7.1.3 to >=7.1.3,<9.0.0. PR [#12745](https://github.com/fastapi/fastapi/pull/12745) by [@dependabot[bot]](https://github.com/apps/dependabot).
* 🔧 Update sponsors: add Render. PR [#12733](https://github.com/fastapi/fastapi/pull/12733) by [@tiangolo](https://github.com/tiangolo).
* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#12707](https://github.com/fastapi/fastapi/pull/12707) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
## 0.115.4
### Refactors
* ♻️ Update logic to import and check `python-multipart` for compatibility with newer version. PR [#12627](https://github.com/fastapi/fastapi/pull/12627) by [@tiangolo](https://github.com/tiangolo).
### Docs
* 📝 Update includes in `docs/fr/docs/tutorial/body.md`. PR [#12596](https://github.com/fastapi/fastapi/pull/12596) by [@kantandane](https://github.com/kantandane).
* 📝 Update includes in `docs/fr/docs/tutorial/debugging.md`. PR [#12595](https://github.com/fastapi/fastapi/pull/12595) by [@kantandane](https://github.com/kantandane).
* 📝 Update includes in `docs/fr/docs/tutorial/query-params-str-validations.md`. PR [#12591](https://github.com/fastapi/fastapi/pull/12591) by [@kantandane](https://github.com/kantandane).
* 📝 Update includes in `docs/fr/docs/tutorial/query-params.md`. PR [#12589](https://github.com/fastapi/fastapi/pull/12589) by [@kantandane](https://github.com/kantandane).
* 📝 Update includes in `docs/en/tutorial/body-fields.md`. PR [#12588](https://github.com/fastapi/fastapi/pull/12588) by [@lucaromagnoli](https://github.com/lucaromagnoli).
* 📝 Update includes in `docs/de/docs/tutorial/response-status-code.md`. PR [#12585](https://github.com/fastapi/fastapi/pull/12585) by [@abejaranoh](https://github.com/abejaranoh).
* 📝 Update includes in `docs/en/docs/tutorial/body.md`. PR [#12586](https://github.com/fastapi/fastapi/pull/12586) by [@lucaromagnoli](https://github.com/lucaromagnoli).
* 📝 Update includes in `docs/en/docs/advanced/behind-a-proxy.md`. PR [#12583](https://github.com/fastapi/fastapi/pull/12583) by [@imjuanleonard](https://github.com/imjuanleonard).
* 📝 Update includes syntax for `docs/pl/docs/tutorial/first-steps.md`. PR [#12584](https://github.com/fastapi/fastapi/pull/12584) by [@sebkozlo](https://github.com/sebkozlo).
* 📝 Update includes in `docs/en/docs/advanced/middleware.md`. PR [#12582](https://github.com/fastapi/fastapi/pull/12582) by [@montanarograziano](https://github.com/montanarograziano).
* 📝 Update includes in `docs/en/docs/advanced/additional-status-codes.md`. PR [#12577](https://github.com/fastapi/fastapi/pull/12577) by [@krishnamadhavan](https://github.com/krishnamadhavan).
* 📝 Update includes in `docs/en/docs/advanced/advanced-dependencies.md`. PR [#12578](https://github.com/fastapi/fastapi/pull/12578) by [@krishnamadhavan](https://github.com/krishnamadhavan).
* 📝 Update includes in `docs/en/docs/advanced/additional-responses.md`. PR [#12576](https://github.com/fastapi/fastapi/pull/12576) by [@krishnamadhavan](https://github.com/krishnamadhavan).
* 📝 Update includes in `docs/en/docs/tutorial/static-files.md`. PR [#12575](https://github.com/fastapi/fastapi/pull/12575) by [@lucaromagnoli](https://github.com/lucaromagnoli).
* 📝 Update includes in `docs/en/docs/advanced/async-tests.md`. PR [#12568](https://github.com/fastapi/fastapi/pull/12568) by [@krishnamadhavan](https://github.com/krishnamadhavan).
* 📝 Update includes in `docs/pt/docs/advanced/behind-a-proxy.md`. PR [#12563](https://github.com/fastapi/fastapi/pull/12563) by [@asmioglou](https://github.com/asmioglou).
* 📝 Update includes in `docs/de/docs/advanced/security/http-basic-auth.md`. PR [#12561](https://github.com/fastapi/fastapi/pull/12561) by [@Nimitha-jagadeesha](https://github.com/Nimitha-jagadeesha).
* 📝 Update includes in `docs/en/docs/tutorial/background-tasks.md`. PR [#12559](https://github.com/fastapi/fastapi/pull/12559) by [@FarhanAliRaza](https://github.com/FarhanAliRaza).
* 📝 Update includes in `docs/fr/docs/python-types.md`. PR [#12558](https://github.com/fastapi/fastapi/pull/12558) by [@Ismailtlem](https://github.com/Ismailtlem).
* 📝 Update includes in `docs/en/docs/how-to/graphql.md`. PR [#12564](https://github.com/fastapi/fastapi/pull/12564) by [@philipokiokio](https://github.com/philipokiokio).
* 📝 Update includes in `docs/en/docs/how-to/extending-openapi.md`. PR [#12562](https://github.com/fastapi/fastapi/pull/12562) by [@philipokiokio](https://github.com/philipokiokio).
* 📝 Update includes for `docs/en/docs/how-to/configure-swagger-ui.md`. PR [#12556](https://github.com/fastapi/fastapi/pull/12556) by [@tiangolo](https://github.com/tiangolo).
* 📝 Update includes for `docs/en/docs/how-to/separate-openapi-schemas.md`. PR [#12555](https://github.com/fastapi/fastapi/pull/12555) by [@tiangolo](https://github.com/tiangolo).
* 📝 Update includes for `docs/en/docs/advanced/security/http-basic-auth.md`. PR [#12553](https://github.com/fastapi/fastapi/pull/12553) by [@tiangolo](https://github.com/tiangolo).
* 📝 Update includes in `docs/en/docs/tutorial/first-steps.md`. PR [#12552](https://github.com/fastapi/fastapi/pull/12552) by [@tiangolo](https://github.com/tiangolo).
* 📝 Update includes in `docs/en/docs/python-types.md`. PR [#12551](https://github.com/fastapi/fastapi/pull/12551) by [@tiangolo](https://github.com/tiangolo).
* 📝 Fix link in OAuth2 docs. PR [#12550](https://github.com/fastapi/fastapi/pull/12550) by [@tiangolo](https://github.com/tiangolo).
* 📝 Add External Link: FastAPI do Zero. PR [#12533](https://github.com/fastapi/fastapi/pull/12533) by [@rennerocha](https://github.com/rennerocha).
* 📝 Fix minor typos. PR [#12516](https://github.com/fastapi/fastapi/pull/12516) by [@kkirsche](https://github.com/kkirsche).
* 🌐 Fix rendering issue in translations. PR [#12509](https://github.com/fastapi/fastapi/pull/12509) by [@alejsdev](https://github.com/alejsdev).
### Translations
* 📝 Update includes in `docs/de/docs/advanced/async-tests.md`. PR [#12567](https://github.com/fastapi/fastapi/pull/12567) by [@imjuanleonard](https://github.com/imjuanleonard).
* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/sql-databases.md`. PR [#12530](https://github.com/fastapi/fastapi/pull/12530) by [@ilacftemp](https://github.com/ilacftemp).
* 🌐 Add Korean translation for `docs/ko/docs/benchmarks.md`. PR [#12540](https://github.com/fastapi/fastapi/pull/12540) by [@Limsunoh](https://github.com/Limsunoh).
* 🌐 Add Portuguese translation for `docs/pt/docs/how-to/separate-openapi-schemas.md`. PR [#12518](https://github.com/fastapi/fastapi/pull/12518) by [@ilacftemp](https://github.com/ilacftemp).
* 🌐 Update Traditional Chinese translation for `docs/zh-hant/docs/deployment/index.md`. PR [#12521](https://github.com/fastapi/fastapi/pull/12521) by [@codingjenny](https://github.com/codingjenny).
* 🌐 Update Traditional Chinese translation for `docs/zh-hant/docs/deployment/cloud.md`. PR [#12522](https://github.com/fastapi/fastapi/pull/12522) by [@codingjenny](https://github.com/codingjenny).
@ -29,6 +110,7 @@ hide:
### Internal
* ⬆ Bump cloudflare/wrangler-action from 3.9 to 3.11. PR [#12544](https://github.com/fastapi/fastapi/pull/12544) by [@dependabot[bot]](https://github.com/apps/dependabot).
* 👷 Update GitHub Action to deploy docs previews to handle missing deploy comments. PR [#12527](https://github.com/fastapi/fastapi/pull/12527) by [@tiangolo](https://github.com/tiangolo).
* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#12505](https://github.com/fastapi/fastapi/pull/12505) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).

62
docs/en/docs/tutorial/background-tasks.md

@ -15,9 +15,7 @@ This includes, for example:
First, import `BackgroundTasks` and define a parameter in your *path operation function* with a type declaration of `BackgroundTasks`:
```Python hl_lines="1 13"
{!../../docs_src/background_tasks/tutorial001.py!}
```
{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *}
**FastAPI** will create the object of type `BackgroundTasks` for you and pass it as that parameter.
@ -33,17 +31,13 @@ In this case, the task function will write to a file (simulating sending an emai
And as the write operation doesn't use `async` and `await`, we define the function with normal `def`:
```Python hl_lines="6-9"
{!../../docs_src/background_tasks/tutorial001.py!}
```
{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *}
## Add the background task
Inside of your *path operation function*, pass your task function to the *background tasks* object with the method `.add_task()`:
```Python hl_lines="14"
{!../../docs_src/background_tasks/tutorial001.py!}
```
{* ../../docs_src/background_tasks/tutorial001.py hl[14] *}
`.add_task()` receives as arguments:
@ -57,57 +51,9 @@ Using `BackgroundTasks` also works with the dependency injection system, you can
**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:
//// tab | Python 3.10+
```Python hl_lines="13 15 22 25"
{!> ../../docs_src/background_tasks/tutorial002_an_py310.py!}
```
{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}
////
//// tab | Python 3.9+
```Python hl_lines="13 15 22 25"
{!> ../../docs_src/background_tasks/tutorial002_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="14 16 23 26"
{!> ../../docs_src/background_tasks/tutorial002_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="11 13 20 23"
{!> ../../docs_src/background_tasks/tutorial002_py310.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="13 15 22 25"
{!> ../../docs_src/background_tasks/tutorial002.py!}
```
////
In this example, the messages will be written to the `log.txt` file *after* the response is sent.

103
docs/en/docs/tutorial/body-fields.md

@ -6,57 +6,8 @@ The same way you can declare additional validation and metadata in *path operati
First, you have to import it:
//// tab | Python 3.10+
{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}
```Python hl_lines="4"
{!> ../../docs_src/body_fields/tutorial001_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="4"
{!> ../../docs_src/body_fields/tutorial001_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="4"
{!> ../../docs_src/body_fields/tutorial001_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="2"
{!> ../../docs_src/body_fields/tutorial001_py310.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="4"
{!> ../../docs_src/body_fields/tutorial001.py!}
```
////
/// warning
@ -68,57 +19,7 @@ Notice that `Field` is imported directly from `pydantic`, not from `fastapi` as
You can then use `Field` with model attributes:
//// tab | Python 3.10+
```Python hl_lines="11-14"
{!> ../../docs_src/body_fields/tutorial001_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="11-14"
{!> ../../docs_src/body_fields/tutorial001_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="12-15"
{!> ../../docs_src/body_fields/tutorial001_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="9-12"
{!> ../../docs_src/body_fields/tutorial001_py310.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="11-14"
{!> ../../docs_src/body_fields/tutorial001.py!}
```
////
{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}
`Field` works the same way as `Query`, `Path` and `Body`, it has all the same parameters, etc.

92
docs/en/docs/tutorial/body.md

@ -22,21 +22,7 @@ As it is discouraged, the interactive docs with Swagger UI won't show the docume
First, you need to import `BaseModel` from `pydantic`:
//// tab | Python 3.10+
```Python hl_lines="2"
{!> ../../docs_src/body/tutorial001_py310.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="4"
{!> ../../docs_src/body/tutorial001.py!}
```
////
{* ../../docs_src/body/tutorial001_py310.py hl[2] *}
## Create your data model
@ -44,21 +30,8 @@ Then you declare your data model as a class that inherits from `BaseModel`.
Use standard Python types for all the attributes:
//// tab | Python 3.10+
```Python hl_lines="5-9"
{!> ../../docs_src/body/tutorial001_py310.py!}
```
////
{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
//// tab | Python 3.8+
```Python hl_lines="7-11"
{!> ../../docs_src/body/tutorial001.py!}
```
////
The 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.
@ -86,21 +59,7 @@ For example, this model above declares a JSON "`object`" (or Python `dict`) like
To add it to your *path operation*, declare it the same way you declared path and query parameters:
//// tab | Python 3.10+
```Python hl_lines="16"
{!> ../../docs_src/body/tutorial001_py310.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="18"
{!> ../../docs_src/body/tutorial001.py!}
```
////
{* ../../docs_src/body/tutorial001_py310.py hl[16] *}
...and declare its type as the model you created, `Item`.
@ -167,21 +126,7 @@ It improves editor support for Pydantic models, with:
Inside of the function, you can access all the attributes of the model object directly:
//// tab | Python 3.10+
```Python hl_lines="19"
{!> ../../docs_src/body/tutorial002_py310.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="21"
{!> ../../docs_src/body/tutorial002.py!}
```
////
## Request body + path parameters
@ -189,21 +134,8 @@ You can declare path parameters and request body at the same time.
**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**.
//// tab | Python 3.10+
```Python hl_lines="15-16"
{!> ../../docs_src/body/tutorial003_py310.py!}
```
////
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
//// tab | Python 3.8+
```Python hl_lines="17-18"
{!> ../../docs_src/body/tutorial003.py!}
```
////
## Request body + path + query parameters
@ -211,21 +143,7 @@ You can also declare **body**, **path** and **query** parameters, all at the sam
**FastAPI** will recognize each of them and take the data from the correct place.
//// tab | Python 3.10+
```Python hl_lines="16"
{!> ../../docs_src/body/tutorial004_py310.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="18"
{!> ../../docs_src/body/tutorial004.py!}
```
////
{* ../../docs_src/body/tutorial004_py310.py hl[16] *}
The function parameters will be recognized as follows:

180
docs/en/docs/tutorial/dependencies/index.md

@ -31,57 +31,7 @@ Let's first focus on the dependency.
It is just a function that can take all the same parameters that a *path operation function* can take:
//// tab | Python 3.10+
```Python hl_lines="8-9"
{!> ../../docs_src/dependencies/tutorial001_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="8-11"
{!> ../../docs_src/dependencies/tutorial001_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="9-12"
{!> ../../docs_src/dependencies/tutorial001_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="6-7"
{!> ../../docs_src/dependencies/tutorial001_py310.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="8-11"
{!> ../../docs_src/dependencies/tutorial001.py!}
```
////
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}
That's it.
@ -113,113 +63,13 @@ Make sure you [Upgrade the FastAPI version](../../deployment/versions.md#upgradi
### Import `Depends`
//// tab | Python 3.10+
```Python hl_lines="3"
{!> ../../docs_src/dependencies/tutorial001_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="3"
{!> ../../docs_src/dependencies/tutorial001_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="3"
{!> ../../docs_src/dependencies/tutorial001_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="1"
{!> ../../docs_src/dependencies/tutorial001_py310.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="3"
{!> ../../docs_src/dependencies/tutorial001.py!}
```
////
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}
### Declare the dependency, in the "dependant"
The same way you use `Body`, `Query`, etc. with your *path operation function* parameters, use `Depends` with a new parameter:
//// tab | Python 3.10+
```Python hl_lines="13 18"
{!> ../../docs_src/dependencies/tutorial001_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="15 20"
{!> ../../docs_src/dependencies/tutorial001_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="16 21"
{!> ../../docs_src/dependencies/tutorial001_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="11 16"
{!> ../../docs_src/dependencies/tutorial001_py310.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="15 20"
{!> ../../docs_src/dependencies/tutorial001.py!}
```
////
{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}
Although you use `Depends` in the parameters of your function the same way you use `Body`, `Query`, etc, `Depends` works a bit differently.
@ -276,29 +126,7 @@ commons: Annotated[dict, Depends(common_parameters)]
But because we are using `Annotated`, we can store that `Annotated` value in a variable and use it in multiple places:
//// tab | Python 3.10+
```Python hl_lines="12 16 21"
{!> ../../docs_src/dependencies/tutorial001_02_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="14 18 23"
{!> ../../docs_src/dependencies/tutorial001_02_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="15 19 24"
{!> ../../docs_src/dependencies/tutorial001_02_an.py!}
```
////
{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}
/// tip

16
docs/en/docs/tutorial/encoder.md

@ -20,21 +20,7 @@ You can use `jsonable_encoder` for that.
It receives an object, like a Pydantic model, and returns a JSON compatible version:
//// tab | Python 3.10+
```Python hl_lines="4 21"
{!> ../../docs_src/encoder/tutorial001_py310.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="5 22"
{!> ../../docs_src/encoder/tutorial001.py!}
```
////
{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}
In this example, it would convert the Pydantic model to a `dict`, and the `datetime` to a `str`.

28
docs/en/docs/tutorial/first-steps.md

@ -2,9 +2,7 @@
The simplest FastAPI file could look like this:
```Python
{!../../docs_src/first_steps/tutorial001.py!}
```
{* ../../docs_src/first_steps/tutorial001.py *}
Copy that to a file `main.py`.
@ -157,9 +155,7 @@ You could also use it to generate code automatically, for clients that communica
### Step 1: import `FastAPI`
```Python hl_lines="1"
{!../../docs_src/first_steps/tutorial001.py!}
```
{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
`FastAPI` is a Python class that provides all the functionality for your API.
@ -173,9 +169,7 @@ You can use all the <a href="https://www.starlette.io/" class="external-link" ta
### Step 2: create a `FastAPI` "instance"
```Python hl_lines="3"
{!../../docs_src/first_steps/tutorial001.py!}
```
{* ../../docs_src/first_steps/tutorial001.py hl[3] *}
Here the `app` variable will be an "instance" of the class `FastAPI`.
@ -244,9 +238,7 @@ We are going to call them "**operations**" too.
#### Define a *path operation decorator*
```Python hl_lines="6"
{!../../docs_src/first_steps/tutorial001.py!}
```
{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
The `@app.get("/")` tells **FastAPI** that the function right below is in charge of handling requests that go to:
@ -300,9 +292,7 @@ This is our "**path operation function**":
* **operation**: is `get`.
* **function**: is the function below the "decorator" (below `@app.get("/")`).
```Python hl_lines="7"
{!../../docs_src/first_steps/tutorial001.py!}
```
{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
This is a Python function.
@ -314,9 +304,7 @@ In this case, it is an `async` function.
You could also define it as a normal function instead of `async def`:
```Python hl_lines="7"
{!../../docs_src/first_steps/tutorial003.py!}
```
{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
/// note
@ -326,9 +314,7 @@ If you don't know the difference, check the [Async: *"In a hurry?"*](../async.md
### Step 5: return the content
```Python hl_lines="8"
{!../../docs_src/first_steps/tutorial001.py!}
```
{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
You can return a `dict`, `list`, singular values as `str`, `int`, etc.

12
docs/en/docs/tutorial/response-status-code.md

@ -8,9 +8,7 @@ The same way you can specify a response model, you can also declare the HTTP sta
* `@app.delete()`
* etc.
```Python hl_lines="6"
{!../../docs_src/response_status_code/tutorial001.py!}
```
{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
/// note
@ -76,9 +74,7 @@ To know more about each status code and which code is for what, check the <a hre
Let's see the previous example again:
```Python hl_lines="6"
{!../../docs_src/response_status_code/tutorial001.py!}
```
{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
`201` is the status code for "Created".
@ -86,9 +82,7 @@ But you don't have to memorize what each of these codes mean.
You can use the convenience variables from `fastapi.status`.
```Python hl_lines="1 6"
{!../../docs_src/response_status_code/tutorial002.py!}
```
{* ../../docs_src/response_status_code/tutorial002.py hl[1,6] *}
They are just a convenience, they hold the same number, but that way you can use the editor's autocomplete to find them:

2
docs/en/docs/tutorial/security/oauth2-jwt.md

@ -72,7 +72,7 @@ It supports many secure hashing algorithms and utilities to work with them.
The recommended algorithm is "Bcrypt".
Make sure you create a [virtual environment](../virtual-environments.md){.internal-link target=_blank}, activate it, and then install PassLib with Bcrypt:
Make sure you create a [virtual environment](../../virtual-environments.md){.internal-link target=_blank}, activate it, and then install PassLib with Bcrypt:
<div class="termy">

4
docs/en/docs/tutorial/static-files.md

@ -7,9 +7,7 @@ You can serve static files automatically from a directory using `StaticFiles`.
* Import `StaticFiles`.
* "Mount" a `StaticFiles()` instance in a specific path.
```Python hl_lines="2 6"
{!../../docs_src/static_files/tutorial001.py!}
```
{* ../../docs_src/static_files/tutorial001.py hl[2,6] *}
/// note | "Technical Details"

6
docs/en/overrides/main.html

@ -82,6 +82,12 @@
<img class="sponsor-image" src="/img/sponsors/liblab-banner.png" />
</a>
</div>
<div class="item">
<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">
<span class="sponsor-badge">sponsor</span>
<img class="sponsor-image" src="/img/sponsors/render-banner.svg" />
</a>
</div>
</div>
</div>
{% endblock %}

104
docs/es/docs/tutorial/cookie-params.md

@ -6,57 +6,7 @@ Puedes definir parámetros de Cookie de la misma manera que defines parámetros
Primero importa `Cookie`:
//// tab | Python 3.10+
```Python hl_lines="3"
{!> ../../docs_src/cookie_params/tutorial001_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="3"
{!> ../../docs_src/cookie_params/tutorial001_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="3"
{!> ../../docs_src/cookie_params/tutorial001_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip | Consejo
Es preferible utilizar la versión `Annotated` si es posible.
///
```Python hl_lines="1"
{!> ../../docs_src/cookie_params/tutorial001_py310.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip | Consejo
Es preferible utilizar la versión `Annotated` si es posible.
///
```Python hl_lines="3"
{!> ../../docs_src/cookie_params/tutorial001.py!}
```
////
{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3]*}
## Declarar parámetros de `Cookie`
@ -64,57 +14,7 @@ Luego declara los parámetros de cookie usando la misma estructura que con `Path
El primer valor es el valor por defecto, puedes pasar todos los parámetros adicionales de validación o anotación:
//// tab | Python 3.10+
```Python hl_lines="9"
{!> ../../docs_src/cookie_params/tutorial001_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="9"
{!> ../../docs_src/cookie_params/tutorial001_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="10"
{!> ../../docs_src/cookie_params/tutorial001_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip | Consejo
Es preferible utilizar la versión `Annotated` si es posible.
///
```Python hl_lines="7"
{!> ../../docs_src/cookie_params/tutorial001_py310.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip | Consejo
Es preferible utilizar la versión `Annotated` si es posible.
///
```Python hl_lines="9"
{!> ../../docs_src/cookie_params/tutorial001.py!}
```
////
{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9]*}
/// note | "Detalles Técnicos"

57
docs/fr/docs/python-types.md

@ -23,9 +23,7 @@ Si vous êtes un expert Python, et que vous savez déjà **tout** sur les annota
Prenons un exemple simple :
```Python
{!../../docs_src/python_types/tutorial001.py!}
```
{*../../docs_src/python_types/tutorial001.py*}
Exécuter ce programe affiche :
@ -39,9 +37,7 @@ La fonction :
* Convertit la première lettre de chaque paramètre en majuscules grâce à `title()`.
* Concatène les résultats avec un espace entre les deux.
```Python hl_lines="2"
{!../../docs_src/python_types/tutorial001.py!}
```
{*../../docs_src/python_types/tutorial001.py hl[2] *}
### Limitations
@ -84,9 +80,7 @@ C'est tout.
Ce sont des annotations de types :
```Python hl_lines="1"
{!../../docs_src/python_types/tutorial002.py!}
```
{*../../docs_src/python_types/tutorial002.py hl[1] *}
À ne pas confondre avec la déclaration de valeurs par défaut comme ici :
@ -114,9 +108,7 @@ Vous pouvez donc dérouler les options jusqu'à trouver la méthode à laquelle
Cette fonction possède déjà des annotations de type :
```Python hl_lines="1"
{!../../docs_src/python_types/tutorial003.py!}
```
{*../../docs_src/python_types/tutorial003.py hl[1] *}
Comme l'éditeur connaît le type des variables, vous n'avez pas seulement l'auto-complétion, mais aussi de la détection d'erreurs :
@ -124,9 +116,7 @@ Comme l'éditeur connaît le type des variables, vous n'avez pas seulement l'aut
Maintenant que vous avez connaissance du problème, convertissez `age` en <abbr title="string">chaîne de caractères</abbr> grâce à `str(age)` :
```Python hl_lines="2"
{!../../docs_src/python_types/tutorial004.py!}
```
{*../../docs_src/python_types/tutorial004.py hl[2] *}
## Déclarer des types
@ -145,9 +135,7 @@ Comme par exemple :
* `bool`
* `bytes`
```Python hl_lines="1"
{!../../docs_src/python_types/tutorial005.py!}
```
{*../../docs_src/python_types/tutorial005.py hl[1] *}
### Types génériques avec des paramètres de types
@ -163,9 +151,7 @@ Par exemple, définissons une variable comme `list` de `str`.
Importez `List` (avec un `L` majuscule) depuis `typing`.
```Python hl_lines="1"
{!../../docs_src/python_types/tutorial006.py!}
```
{*../../docs_src/python_types/tutorial006.py hl[1] *}
Déclarez la variable, en utilisant la syntaxe des deux-points (`:`).
@ -173,9 +159,7 @@ Et comme type, mettez `List`.
Les listes étant un type contenant des types internes, mettez ces derniers entre crochets (`[`, `]`) :
```Python hl_lines="4"
{!../../docs_src/python_types/tutorial006.py!}
```
{*../../docs_src/python_types/tutorial006.py hl[4] *}
/// tip | "Astuce"
@ -201,9 +185,7 @@ Et pourtant, l'éditeur sait qu'elle est de type `str` et pourra donc vous aider
C'est le même fonctionnement pour déclarer un `tuple` ou un `set` :
```Python hl_lines="1 4"
{!../../docs_src/python_types/tutorial007.py!}
```
{*../../docs_src/python_types/tutorial007.py hl[1,4] *}
Dans cet exemple :
@ -216,9 +198,7 @@ Pour définir un `dict`, il faut lui passer 2 paramètres, séparés par une vir
Le premier paramètre de type est pour les clés et le second pour les valeurs du dictionnaire (`dict`).
```Python hl_lines="1 4"
{!../../docs_src/python_types/tutorial008.py!}
```
{*../../docs_src/python_types/tutorial008.py hl[1,4] *}
Dans cet exemple :
@ -230,9 +210,7 @@ Dans cet exemple :
Vous pouvez aussi utiliser `Optional` pour déclarer qu'une variable a un type, comme `str` mais qu'il est "optionnel" signifiant qu'il pourrait aussi être `None`.
```Python hl_lines="1 4"
{!../../docs_src/python_types/tutorial009.py!}
```
{*../../docs_src/python_types/tutorial009.py hl[1,4] *}
Utiliser `Optional[str]` plutôt que `str` permettra à l'éditeur de vous aider à détecter les erreurs où vous supposeriez qu'une valeur est toujours de type `str`, alors qu'elle pourrait aussi être `None`.
@ -255,15 +233,12 @@ Vous pouvez aussi déclarer une classe comme type d'une variable.
Disons que vous avez une classe `Person`, avec une variable `name` :
```Python hl_lines="1-3"
{!../../docs_src/python_types/tutorial010.py!}
```
{*../../docs_src/python_types/tutorial010.py hl[1:3] *}
Vous pouvez ensuite déclarer une variable de type `Person` :
```Python hl_lines="6"
{!../../docs_src/python_types/tutorial010.py!}
```
{*../../docs_src/python_types/tutorial010.py hl[6] *}
Et vous aurez accès, encore une fois, au support complet offert par l'éditeur :
@ -283,9 +258,7 @@ Ainsi, votre éditeur vous offrira un support adapté pour l'objet résultant.
Extrait de la documentation officielle de **Pydantic** :
```Python
{!../../docs_src/python_types/tutorial011.py!}
```
{*../../docs_src/python_types/tutorial011.py*}
/// info

16
docs/fr/docs/tutorial/background-tasks.md

@ -16,9 +16,7 @@ Cela comprend, par exemple :
Pour commencer, importez `BackgroundTasks` et définissez un paramètre dans votre *fonction de chemin* avec `BackgroundTasks` comme type déclaré.
```Python hl_lines="1 13"
{!../../docs_src/background_tasks/tutorial001.py!}
```
{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *}
**FastAPI** créera l'objet de type `BackgroundTasks` pour vous et le passera comme paramètre.
@ -32,18 +30,14 @@ Dans cet exemple, la fonction de tâche écrira dans un fichier (afin de simuler
L'opération d'écriture n'utilisant ni `async` ni `await`, on définit la fonction avec un `def` normal.
```Python hl_lines="6-9"
{!../../docs_src/background_tasks/tutorial001.py!}
```
{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *}
## Ajouter une tâche d'arrière-plan
Dans votre *fonction de chemin*, passez votre fonction de tâche à l'objet de type `BackgroundTasks` (`background_tasks` ici) grâce à la méthode `.add_task()` :
```Python hl_lines="14"
{!../../docs_src/background_tasks/tutorial001.py!}
```
{* ../../docs_src/background_tasks/tutorial001.py hl[14] *}
`.add_task()` reçoit comme arguments :
@ -57,9 +51,7 @@ Utiliser `BackgroundTasks` fonctionne aussi avec le système d'injection de dép
**FastAPI** sait quoi faire dans chaque cas et comment réutiliser le même objet, afin que tous les paramètres de type `BackgroundTasks` soient fusionnés et que les tâches soient exécutées en arrière-plan :
```Python hl_lines="13 15 22 25"
{!../../docs_src/background_tasks/tutorial002.py!}
```
{* ../../docs_src/background_tasks/tutorial002.py hl[13,15,22,25] *}
Dans cet exemple, les messages seront écrits dans le fichier `log.txt` après que la réponse soit envoyée.

24
docs/fr/docs/tutorial/body.md

@ -22,9 +22,7 @@ Ceci étant découragé, la documentation interactive générée par Swagger UI
Commencez par importer la classe `BaseModel` du module `pydantic` :
```Python hl_lines="4"
{!../../docs_src/body/tutorial001.py!}
```
{* ../../docs_src/body/tutorial001.py hl[4] *}
## Créez votre modèle de données
@ -32,9 +30,7 @@ Déclarez ensuite votre modèle de données en tant que classe qui hérite de `B
Utilisez les types Python standard pour tous les attributs :
```Python hl_lines="7-11"
{!../../docs_src/body/tutorial001.py!}
```
{* ../../docs_src/body/tutorial001.py hl[7:11] *}
Tout comme pour la déclaration de paramètres de requête, quand un attribut de modèle a une valeur par défaut, il n'est pas nécessaire. Sinon, cet attribut doit être renseigné dans le corps de la requête. Pour rendre ce champ optionnel simplement, utilisez `None` comme valeur par défaut.
@ -62,9 +58,7 @@ Par exemple, le modèle ci-dessus déclare un "objet" JSON (ou `dict` Python) te
Pour l'ajouter à votre *opération de chemin*, déclarez-le comme vous déclareriez des paramètres de chemin ou de requête :
```Python hl_lines="18"
{!../../docs_src/body/tutorial001.py!}
```
{* ../../docs_src/body/tutorial001.py hl[18] *}
...et déclarez que son type est le modèle que vous avez créé : `Item`.
@ -131,9 +125,7 @@ Ce qui améliore le support pour les modèles Pydantic avec :
Dans la fonction, vous pouvez accéder à tous les attributs de l'objet du modèle directement :
```Python hl_lines="21"
{!../../docs_src/body/tutorial002.py!}
```
{* ../../docs_src/body/tutorial002.py hl[21] *}
## Corps de la requête + paramètres de chemin
@ -141,9 +133,7 @@ Vous pouvez déclarer des paramètres de chemin et un corps de requête pour la
**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**.
```Python hl_lines="17-18"
{!../../docs_src/body/tutorial003.py!}
```
{* ../../docs_src/body/tutorial003.py hl[17:18] *}
## Corps de la requête + paramètres de chemin et de requête
@ -151,9 +141,7 @@ Vous pouvez aussi déclarer un **corps**, et des paramètres de **chemin** et de
**FastAPI** saura reconnaître chacun d'entre eux et récupérer la bonne donnée au bon endroit.
```Python hl_lines="18"
{!../../docs_src/body/tutorial004.py!}
```
{* ../../docs_src/body/tutorial004.py hl[18] *}
Les paramètres de la fonction seront reconnus comme tel :

4
docs/fr/docs/tutorial/debugging.md

@ -6,9 +6,7 @@ Vous pouvez connecter le <abbr title="En anglais: debugger">débogueur</abbr> da
Dans votre application FastAPI, importez et exécutez directement `uvicorn` :
```Python hl_lines="1 15"
{!../../docs_src/debugging/tutorial001.py!}
```
{* ../../docs_src/debugging/tutorial001.py hl[1,15] *}
### À propos de `__name__ == "__main__"`

274
docs/fr/docs/tutorial/path-params-numeric-validations.md

@ -6,57 +6,7 @@ De la même façon que vous pouvez déclarer plus de validations et de métadonn
Tout d'abord, importez `Path` de `fastapi`, et importez `Annotated` :
//// tab | Python 3.10+
```Python hl_lines="1 3"
{!> ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="1 3"
{!> ../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="3-4"
{!> ../../docs_src/path_params_numeric_validations/tutorial001_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Préférez utiliser la version `Annotated` si possible.
///
```Python hl_lines="1"
{!> ../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Préférez utiliser la version `Annotated` si possible.
///
```Python hl_lines="3"
{!> ../../docs_src/path_params_numeric_validations/tutorial001.py!}
```
////
{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}
/// info
@ -74,57 +24,7 @@ Vous pouvez déclarer les mêmes paramètres que pour `Query`.
Par exemple, pour déclarer une valeur de métadonnée `title` pour le paramètre de chemin `item_id`, vous pouvez écrire :
//// tab | Python 3.10+
```Python hl_lines="10"
{!> ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="10"
{!> ../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="11"
{!> ../../docs_src/path_params_numeric_validations/tutorial001_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip
Préférez utiliser la version `Annotated` si possible.
///
```Python hl_lines="8"
{!> ../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Préférez utiliser la version `Annotated` si possible.
///
```Python hl_lines="10"
{!> ../../docs_src/path_params_numeric_validations/tutorial001.py!}
```
////
{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}
/// note
@ -154,37 +54,11 @@ Cela n'a pas d'importance pour **FastAPI**. Il détectera les paramètres par le
Ainsi, vous pouvez déclarer votre fonction comme suit :
//// tab | Python 3.8 non-Annotated
/// tip
Préférez utiliser la version `Annotated` si possible.
///
```Python hl_lines="7"
{!> ../../docs_src/path_params_numeric_validations/tutorial002.py!}
```
////
{* ../../docs_src/path_params_numeric_validations/tutorial002.py hl[7] *}
Mais 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()`.
//// tab | Python 3.9+
```Python hl_lines="10"
{!> ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="9"
{!> ../../docs_src/path_params_numeric_validations/tutorial002_an.py!}
```
////
{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py hl[10] *}
## Ordonnez les paramètres comme vous le souhaitez (astuces)
@ -209,29 +83,13 @@ Passez `*`, comme premier paramètre de la fonction.
Python 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.
```Python hl_lines="7"
{!../../docs_src/path_params_numeric_validations/tutorial003.py!}
```
{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *}
# Avec `Annotated`
Gardez à 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 `*`.
//// tab | Python 3.9+
```Python hl_lines="10"
{!> ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="9"
{!> ../../docs_src/path_params_numeric_validations/tutorial003_an.py!}
```
////
{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *}
## Validations numériques : supérieur ou égal
@ -239,35 +97,7 @@ Avec `Query` et `Path` (et d'autres que vous verrez plus tard) vous pouvez décl
Ici, avec `ge=1`, `item_id` devra être un nombre entier "`g`reater than or `e`qual" à `1`.
//// tab | Python 3.9+
```Python hl_lines="10"
{!> ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="9"
{!> ../../docs_src/path_params_numeric_validations/tutorial004_an.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Prefer to use the `Annotated` version if possible.
///
```Python hl_lines="8"
{!> ../../docs_src/path_params_numeric_validations/tutorial004.py!}
```
////
{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
## Validations numériques : supérieur ou égal et inférieur ou égal
@ -276,35 +106,7 @@ La même chose s'applique pour :
* `gt` : `g`reater `t`han
* `le` : `l`ess than or `e`qual
//// tab | Python 3.9+
```Python hl_lines="10"
{!> ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="9"
{!> ../../docs_src/path_params_numeric_validations/tutorial004_an.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Préférez utiliser la version `Annotated` si possible.
///
```Python hl_lines="8"
{!> ../../docs_src/path_params_numeric_validations/tutorial004.py!}
```
////
{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
## Validations numériques : supérieur et inférieur ou égal
@ -313,35 +115,7 @@ La même chose s'applique pour :
* `gt` : `g`reater `t`han
* `le` : `l`ess than or `e`qual
//// tab | Python 3.9+
```Python hl_lines="10"
{!> ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="9"
{!> ../../docs_src/path_params_numeric_validations/tutorial005_an.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Préférez utiliser la version `Annotated` si possible.
///
```Python hl_lines="9"
{!> ../../docs_src/path_params_numeric_validations/tutorial005.py!}
```
////
{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *}
## Validations numériques : flottants, supérieur et inférieur
@ -353,35 +127,7 @@ Ainsi, `0.5` serait une valeur valide. Mais `0.0` ou `0` ne le serait pas.
Et la même chose pour <abbr title="less than"><code>lt</code></abbr>.
//// tab | Python 3.9+
```Python hl_lines="13"
{!> ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="12"
{!> ../../docs_src/path_params_numeric_validations/tutorial006_an.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip
Préférez utiliser la version `Annotated` si possible.
///
```Python hl_lines="11"
{!> ../../docs_src/path_params_numeric_validations/tutorial006.py!}
```
////
{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *}
## Pour résumer

56
docs/fr/docs/tutorial/query-params-str-validations.md

@ -4,9 +4,7 @@
Commençons avec cette application pour exemple :
```Python hl_lines="9"
{!../../docs_src/query_params_str_validations/tutorial001.py!}
```
{* ../../docs_src/query_params_str_validations/tutorial001.py hl[9] *}
Le paramètre de requête `q` a pour type `Union[str, None]` (ou `str | None` en Python 3.10), signifiant qu'il est de type `str` mais pourrait aussi être égal à `None`, et bien sûr, la valeur par défaut est `None`, donc **FastAPI** saura qu'il n'est pas requis.
@ -26,17 +24,13 @@ Nous allons imposer que bien que `q` soit un paramètre optionnel, dès qu'il es
Pour cela, importez d'abord `Query` depuis `fastapi` :
```Python hl_lines="3"
{!../../docs_src/query_params_str_validations/tutorial002.py!}
```
{* ../../docs_src/query_params_str_validations/tutorial002.py hl[3] *}
## Utiliser `Query` comme valeur par défaut
Construisez ensuite la valeur par défaut de votre paramètre avec `Query`, en choisissant 50 comme `max_length` :
```Python hl_lines="9"
{!../../docs_src/query_params_str_validations/tutorial002.py!}
```
{* ../../docs_src/query_params_str_validations/tutorial002.py hl[9] *}
Comme nous devons remplacer la valeur par défaut `None` dans la fonction par `Query()`, nous pouvons maintenant définir la valeur par défaut avec le paramètre `Query(default=None)`, il sert le même objectif qui est de définir cette valeur par défaut.
@ -86,17 +80,13 @@ Cela va valider les données, montrer une erreur claire si ces dernières ne son
Vous pouvez aussi rajouter un second paramètre `min_length` :
```Python hl_lines="9"
{!../../docs_src/query_params_str_validations/tutorial003.py!}
```
{* ../../docs_src/query_params_str_validations/tutorial003.py hl[9] *}
## Ajouter des validations par expressions régulières
On peut définir une <abbr title="Une expression régulière, regex ou regexp est une suite de caractères qui définit un pattern de correspondance pour les chaînes de caractères.">expression régulière</abbr> à laquelle le paramètre doit correspondre :
```Python hl_lines="10"
{!../../docs_src/query_params_str_validations/tutorial004.py!}
```
{* ../../docs_src/query_params_str_validations/tutorial004.py hl[10] *}
Cette expression régulière vérifie que la valeur passée comme paramètre :
@ -114,9 +104,7 @@ De la même façon que vous pouvez passer `None` comme premier argument pour l'u
Disons que vous déclarez le paramètre `q` comme ayant une longueur minimale de `3`, et une valeur par défaut étant `"fixedquery"` :
```Python hl_lines="7"
{!../../docs_src/query_params_str_validations/tutorial005.py!}
```
{* ../../docs_src/query_params_str_validations/tutorial005.py hl[7] *}
/// note | "Rappel"
@ -146,9 +134,7 @@ q: Union[str, None] = Query(default=None, min_length=3)
Donc pour déclarer une valeur comme requise tout en utilisant `Query`, il faut utiliser `...` comme premier argument :
```Python hl_lines="7"
{!../../docs_src/query_params_str_validations/tutorial006.py!}
```
{* ../../docs_src/query_params_str_validations/tutorial006.py hl[7] *}
/// info
@ -164,9 +150,7 @@ Quand on définit un paramètre de requête explicitement avec `Query` on peut a
Par exemple, pour déclarer un paramètre de requête `q` qui peut apparaître plusieurs fois dans une URL, on écrit :
```Python hl_lines="9"
{!../../docs_src/query_params_str_validations/tutorial011.py!}
```
{* ../../docs_src/query_params_str_validations/tutorial011.py hl[9] *}
Ce qui fait qu'avec une URL comme :
@ -201,9 +185,7 @@ La documentation sera donc mise à jour automatiquement pour autoriser plusieurs
Et l'on peut aussi définir une liste de valeurs par défaut si aucune n'est fournie :
```Python hl_lines="9"
{!../../docs_src/query_params_str_validations/tutorial012.py!}
```
{* ../../docs_src/query_params_str_validations/tutorial012.py hl[9] *}
Si vous allez à :
@ -228,9 +210,7 @@ et la réponse sera :
Il est aussi possible d'utiliser directement `list` plutôt que `List[str]` :
```Python hl_lines="7"
{!../../docs_src/query_params_str_validations/tutorial013.py!}
```
{* ../../docs_src/query_params_str_validations/tutorial013.py hl[7] *}
/// note
@ -256,15 +236,11 @@ Il se peut donc que certains d'entre eux n'utilisent pas toutes les métadonnée
Vous pouvez ajouter un `title` :
```Python hl_lines="10"
{!../../docs_src/query_params_str_validations/tutorial007.py!}
```
{* ../../docs_src/query_params_str_validations/tutorial007.py hl[10] *}
Et une `description` :
```Python hl_lines="13"
{!../../docs_src/query_params_str_validations/tutorial008.py!}
```
{* ../../docs_src/query_params_str_validations/tutorial008.py hl[13] *}
## Alias de paramètres
@ -284,9 +260,7 @@ Mais vous avez vraiment envie que ce soit exactement `item-query`...
Pour cela vous pouvez déclarer un `alias`, et cet alias est ce qui sera utilisé pour trouver la valeur du paramètre :
```Python hl_lines="9"
{!../../docs_src/query_params_str_validations/tutorial009.py!}
```
{* ../../docs_src/query_params_str_validations/tutorial009.py hl[9] *}
## Déprécier des paramètres
@ -296,9 +270,7 @@ Il faut qu'il continue à exister pendant un certain temps car vos clients l'uti
On utilise alors l'argument `deprecated=True` de `Query` :
```Python hl_lines="18"
{!../../docs_src/query_params_str_validations/tutorial010.py!}
```
{* ../../docs_src/query_params_str_validations/tutorial010.py hl[18] *}
La documentation le présentera comme il suit :

24
docs/fr/docs/tutorial/query-params.md

@ -2,9 +2,7 @@
Quand vous déclarez des paramètres dans votre fonction de chemin qui ne font pas partie des paramètres indiqués dans le chemin associé, ces paramètres sont automatiquement considérés comme des paramètres de "requête".
```Python hl_lines="9"
{!../../docs_src/query_params/tutorial001.py!}
```
{* ../../docs_src/query_params/tutorial001.py hl[9] *}
La partie appelée requête (ou **query**) dans une URL est l'ensemble des paires clés-valeurs placées après le `?` , séparées par des `&`.
@ -63,9 +61,7 @@ Les valeurs des paramètres de votre fonction seront :
De la même façon, vous pouvez définir des paramètres de requête comme optionnels, en leur donnant comme valeur par défaut `None` :
```Python hl_lines="9"
{!../../docs_src/query_params/tutorial002.py!}
```
{* ../../docs_src/query_params/tutorial002.py hl[9] *}
Ici, le paramètre `q` sera optionnel, et aura `None` comme valeur par défaut.
@ -87,9 +83,7 @@ Le `Optional` dans `Optional[str]` n'est pas utilisé par **FastAPI** (**FastAPI
Vous pouvez aussi déclarer des paramètres de requête comme booléens (`bool`), **FastAPI** les convertira :
```Python hl_lines="9"
{!../../docs_src/query_params/tutorial003.py!}
```
{* ../../docs_src/query_params/tutorial003.py hl[9] *}
Avec ce code, en allant sur :
@ -131,9 +125,7 @@ Et vous n'avez pas besoin de les déclarer dans un ordre spécifique.
Ils seront détectés par leurs noms :
```Python hl_lines="8 10"
{!../../docs_src/query_params/tutorial004.py!}
```
{* ../../docs_src/query_params/tutorial004.py hl[8,10] *}
## Paramètres de requête requis
@ -143,9 +135,7 @@ Si vous ne voulez pas leur donner de valeur par défaut mais juste les rendre op
Mais si vous voulez rendre un paramètre de requête obligatoire, vous pouvez juste ne pas y affecter de valeur par défaut :
```Python hl_lines="6-7"
{!../../docs_src/query_params/tutorial005.py!}
```
{* ../../docs_src/query_params/tutorial005.py hl[6:7] *}
Ici le paramètre `needy` est un paramètre requis (ou obligatoire) de type `str`.
@ -189,9 +179,7 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
Et bien sur, vous pouvez définir certains paramètres comme requis, certains avec des valeurs par défaut et certains entièrement optionnels :
```Python hl_lines="10"
{!../../docs_src/query_params/tutorial006.py!}
```
{* ../../docs_src/query_params/tutorial006.py hl[10] *}
Ici, on a donc 3 paramètres de requête :

33
docs/ko/docs/advanced/response-change-status-code.md

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

53
docs/ko/docs/advanced/response-cookies.md

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

67
docs/ko/docs/advanced/response-directly.md

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

37
docs/ko/docs/advanced/wsgi.md

@ -0,0 +1,37 @@
# WSGI 포함하기 - Flask, Django 그 외
[서브 응용 프로그램 - 마운트](sub-applications.md){.internal-link target=_blank}, [프록시 뒤편에서](behind-a-proxy.md){.internal-link target=_blank}에서 보았듯이 WSGI 응용 프로그램들을 다음과 같이 마운트 할 수 있습니다.
`WSGIMiddleware`를 사용하여 WSGI 응용 프로그램(예: Flask, Django 등)을 감쌀 수 있습니다.
## `WSGIMiddleware` 사용하기
`WSGIMiddleware`를 불러와야 합니다.
그런 다음, WSGI(예: Flask) 응용 프로그램을 미들웨어로 포장합니다.
그 후, 해당 경로에 마운트합니다.
```Python hl_lines="2-3 23"
{!../../docs_src/wsgi/tutorial001.py!}
```
## 확인하기
이제 `/v1/` 경로에 있는 모든 요청은 Flask 응용 프로그램에서 처리됩니다.
그리고 나머지는 **FastAPI**에 의해 처리됩니다.
실행하면 <a href="http://localhost:8000/v1/" class="external-link" target="_blank">http://localhost:8000/v1/</a>으로 이동해서 Flask의 응답을 볼 수 있습니다:
```txt
Hello, World from Flask!
```
그리고 다음으로 이동하면 <a href="http://localhost:8000/v2" class="external-link" target="_blank">http://localhost:8000/v2</a> Flask의 응답을 볼 수 있습니다:
```JSON
{
"message": "Hello World"
}
```

34
docs/ko/docs/benchmarks.md

@ -0,0 +1,34 @@
# 벤치마크
독립적인 TechEmpower 벤치마크에 따르면 **FastAPI** 애플리케이션이 Uvicorn을 사용하여 <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">가장 빠른 Python 프레임워크 중 하나</a>로 실행되며, Starlette와 Uvicorn 자체(내부적으로 FastAPI가 사용하는 도구)보다 조금 아래에 위치합니다.
그러나 벤치마크와 비교를 확인할 때 다음 사항을 염두에 두어야 합니다.
## 벤치마크와 속도
벤치마크를 확인할 때, 일반적으로 여러 가지 유형의 도구가 동등한 것으로 비교되는 것을 볼 수 있습니다.
특히, Uvicorn, Starlette, FastAPI가 함께 비교되는 경우가 많습니다(다른 여러 도구와 함께).
도구가 해결하는 문제가 단순할수록 성능이 더 좋아집니다. 그리고 대부분의 벤치마크는 도구가 제공하는 추가 기능을 테스트하지 않습니다.
계층 구조는 다음과 같습니다:
* **Uvicorn**: ASGI 서버
* **Starlette**: (Uvicorn 사용) 웹 마이크로 프레임워크
* **FastAPI**: (Starlette 사용) API 구축을 위한 데이터 검증 등 여러 추가 기능이 포함된 API 마이크로 프레임워크
* **Uvicorn**:
* 서버 자체 외에는 많은 추가 코드가 없기 때문에 최고의 성능을 발휘합니다.
* 직접 Uvicorn으로 응용 프로그램을 작성하지는 않을 것입니다. 즉, 사용자의 코드에는 적어도 Starlette(또는 **FastAPI**)에서 제공하는 모든 코드가 포함되어야 합니다. 그렇게 하면 최종 응용 프로그램은 프레임워크를 사용하고 앱 코드와 버그를 최소화하는 것과 동일한 오버헤드를 갖게 됩니다.
* Uvicorn을 비교할 때는 Daphne, Hypercorn, uWSGI 등의 응용 프로그램 서버와 비교하세요.
* **Starlette**:
* Uvicorn 다음으로 좋은 성능을 발휘합니다. 사실 Starlette는 Uvicorn을 사용하여 실행됩니다. 따라서 더 많은 코드를 실행해야 하기 때문에 Uvicorn보다 "느려질" 수밖에 없습니다.
* 하지만 경로 기반 라우팅 등 간단한 웹 응용 프로그램을 구축할 수 있는 도구를 제공합니다.
* Starlette를 비교할 때는 Sanic, Flask, Django 등의 웹 프레임워크(또는 마이크로 프레임워크)와 비교하세요.
* **FastAPI**:
* Starlette가 Uvicorn을 사용하므로 Uvicorn보다 빨라질 수 없는 것과 마찬가지로, **FastAPI**는 Starlette를 사용하므로 더 빠를 수 없습니다.
* FastAPI는 Starlette에 추가적으로 더 많은 기능을 제공합니다. API를 구축할 때 거의 항상 필요한 데이터 검증 및 직렬화와 같은 기능들이 포함되어 있습니다. 그리고 이를 사용하면 문서 자동화 기능도 제공됩니다(문서 자동화는 응용 프로그램 실행 시 오버헤드를 추가하지 않고 시작 시 생성됩니다).
* FastAPI를 사용하지 않고 직접 Starlette(또는 Sanic, Flask, Responder 등)를 사용했다면 데이터 검증 및 직렬화를 직접 구현해야 합니다. 따라서 최종 응용 프로그램은 FastAPI를 사용한 것과 동일한 오버헤드를 가지게 될 것입니다. 많은 경우 데이터 검증 및 직렬화가 응용 프로그램에서 작성된 코드 중 가장 많은 부분을 차지합니다.
* 따라서 FastAPI를 사용함으로써 개발 시간, 버그, 코드 라인을 줄일 수 있으며, FastAPI를 사용하지 않았을 때와 동일하거나 더 나은 성능을 얻을 수 있습니다(코드에서 모두 구현해야 하기 때문에).
* FastAPI를 비교할 때는 Flask-apispec, NestJS, Molten 등 데이터 검증, 직렬화 및 문서화가 통합된 자동 데이터 검증, 직렬화 및 문서화를 제공하는 웹 응용 프로그램 프레임워크(또는 도구 집합)와 비교하세요.

83
docs/ko/docs/fastapi-cli.md

@ -0,0 +1,83 @@
# FastAPI CLI
**FastAPI CLI**는 FastAPI 애플리케이션을 실행하고, 프로젝트를 관리하는 등 다양한 작업을 수행할 수 있는 커맨드 라인 프로그램입니다.
FastAPI를 설치할 때 (예: `pip install "fastapi[standard]"` 명령어를 사용할 경우), `fastapi-cli`라는 패키지가 포함됩니다. 이 패키지는 터미널에서 사용할 수 있는 `fastapi` 명령어를 제공합니다.
개발용으로 FastAPI 애플리케이션을 실행하려면 다음과 같이 `fastapi dev` 명령어를 사용할 수 있습니다:
<div class="termy">
```console
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:single">main.py</u>
<font color="#3465A4">INFO </font> Using path <font color="#3465A4">main.py</font>
<font color="#3465A4">INFO </font> Resolved absolute path <font color="#75507B">/home/user/code/awesomeapp/</font><font color="#AD7FA8">main.py</font>
<font color="#3465A4">INFO </font> Searching for package file structure from directories with <font color="#3465A4">__init__.py</font> files
<font color="#3465A4">INFO </font> Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
╭─ <font color="#8AE234"><b>Python module file</b></font> ─╮
│ │
│ 🐍 main.py │
│ │
╰──────────────────────╯
<font color="#3465A4">INFO </font> Importing module <font color="#4E9A06">main</font>
<font color="#3465A4">INFO </font> Found importable FastAPI app
╭─ <font color="#8AE234"><b>Importable FastAPI app</b></font> ─╮
│ │
<span style="background-color:#272822"><font color="#FF4689">from</font></span><span style="background-color:#272822"><font color="#F8F8F2"> main </font></span><span style="background-color:#272822"><font color="#FF4689">import</font></span><span style="background-color:#272822"><font color="#F8F8F2"> app</font></span><span style="background-color:#272822"> </span>
│ │
╰──────────────────────────╯
<font color="#3465A4">INFO </font> Using import string <font color="#8AE234"><b>main:app</b></font>
<span style="background-color:#C4A000"><font color="#2E3436">╭────────── FastAPI CLI - Development mode ───────────╮</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ Serving at: http://127.0.0.1:8000 │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ API docs: http://127.0.0.1:8000/docs │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ Running in development mode, for production use: │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436"></font></span><span style="background-color:#C4A000"><font color="#555753"><b>fastapi run</b></font></span><span style="background-color:#C4A000"><font color="#2E3436"></font></span>
<span style="background-color:#C4A000"><font color="#2E3436">│ │</font></span>
<span style="background-color:#C4A000"><font color="#2E3436">╰─────────────────────────────────────────────────────╯</font></span>
<font color="#4E9A06">INFO</font>: Will watch for changes in these directories: [&apos;/home/user/code/awesomeapp&apos;]
<font color="#4E9A06">INFO</font>: Uvicorn running on <b>http://127.0.0.1:8000</b> (Press CTRL+C to quit)
<font color="#4E9A06">INFO</font>: Started reloader process [<font color="#34E2E2"><b>2265862</b></font>] using <font color="#34E2E2"><b>WatchFiles</b></font>
<font color="#4E9A06">INFO</font>: Started server process [<font color="#06989A">2265873</font>]
<font color="#4E9A06">INFO</font>: Waiting for application startup.
<font color="#4E9A06">INFO</font>: Application startup complete.
```
</div>
`fastapi`라고 불리는 명령어 프로그램은 **FastAPI CLI**입니다.
FastAPI CLI는 Python 프로그램의 경로(예: `main.py`)를 인수로 받아, `FastAPI` 인스턴스(일반적으로 `app`으로 명명)를 자동으로 감지하고 올바른 임포트 과정을 결정한 후 이를 실행합니다.
프로덕션 환경에서는 `fastapi run` 명령어를 사용합니다. 🚀
내부적으로, **FastAPI CLI**는 고성능의, 프로덕션에 적합한, ASGI 서버인 <a href="https://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a>을 사용합니다. 😎
## `fastapi dev`
`fastapi dev` 명령을 실행하면 개발 모드가 시작됩니다.
기본적으로 **자동 재시작(auto-reload)** 기능이 활성화되어, 코드에 변경이 생기면 서버를 자동으로 다시 시작합니다. 하지만 이 기능은 리소스를 많이 사용하며, 비활성화했을 때보다 안정성이 떨어질 수 있습니다. 따라서 개발 환경에서만 사용하는 것이 좋습니다. 또한, 서버는 컴퓨터가 자체적으로 통신할 수 있는 IP 주소(`localhost`)인 `127.0.0.1`에서 연결을 대기합니다.
## `fastapi run`
`fastapi run` 명령을 실행하면 기본적으로 프로덕션 모드로 FastAPI가 시작됩니다.
기본적으로 **자동 재시작(auto-reload)** 기능이 비활성화되어 있습니다. 또한, 사용 가능한 모든 IP 주소인 `0.0.0.0`에서 연결을 대기하므로 해당 컴퓨터와 통신할 수 있는 모든 사람이 공개적으로 액세스할 수 있습니다. 이는 일반적으로 컨테이너와 같은 프로덕션 환경에서 실행하는 방법입니다.
애플리케이션을 배포하는 방식에 따라 다르지만, 대부분 "종료 프록시(termination proxy)"를 활용해 HTTPS를 처리하는 것이 좋습니다. 배포 서비스 제공자가 이 작업을 대신 처리해줄 수도 있고, 직접 설정해야 할 수도 있습니다.
/// tip
자세한 내용은 [deployment documentation](deployment/index.md){.internal-link target=\_blank}에서 확인할 수 있습니다.
///

131
docs/ko/docs/tutorial/metadata.md

@ -0,0 +1,131 @@
# 메타데이터 및 문서화 URL
**FastAPI** 응용 프로그램에서 다양한 메타데이터 구성을 사용자 맞춤 설정할 수 있습니다.
## API에 대한 메타데이터
OpenAPI 명세 및 자동화된 API 문서 UI에 사용되는 다음 필드를 설정할 수 있습니다:
| 매개변수 | 타입 | 설명 |
|----------|------|-------|
| `title` | `str` | API의 제목입니다. |
| `summary` | `str` | API에 대한 짧은 요약입니다. <small>OpenAPI 3.1.0, FastAPI 0.99.0부터 사용 가능</small> |
| `description` | `str` | API에 대한 짧은 설명입니다. 마크다운을 사용할 수 있습니다. |
| `version` | `string` | API의 버전입니다. OpenAPI의 버전이 아닌, 여러분의 애플리케이션의 버전을 나타냅니다. 예: `2.5.0` |
| `terms_of_service` | `str` | API 이용 약관의 URL입니다. 제공하는 경우 URL 형식이어야 합니다. |
| `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> |
| `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에 대한 <a href="https://spdx.org/licenses/" class="external-link" target="_blank">SPDX</a> 라이선스 표현입니다. <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> |
다음과 같이 설정할 수 있습니다:
```Python hl_lines="3-16 19-32"
{!../../docs_src/metadata/tutorial001.py!}
```
/// tip
`description` 필드에 마크다운을 사용할 수 있으며, 출력에서 렌더링됩니다.
///
이 구성을 사용하면 문서 자동화(로 생성된) API 문서는 다음과 같이 보입니다:
<img src="/img/tutorial/metadata/image01.png">
## 라이선스 식별자
OpenAPI 3.1.0 및 FastAPI 0.99.0부터 `license_info``identifier`를 URL 대신 설정할 수 있습니다.
예:
```Python hl_lines="31"
{!../../docs_src/metadata/tutorial001_1.py!}
```
## 태그에 대한 메타데이터
`openapi_tags` 매개변수를 사용하여 경로 작동을 그룹화하는 데 사용되는 태그에 추가 메타데이터를 추가할 수 있습니다.
리스트는 각 태그에 대해 하나의 딕셔너리를 포함해야 합니다.
각 딕셔너리에는 다음이 포함될 수 있습니다:
* `name` (**필수**): `tags` 매개변수에서 *경로 작동*과 `APIRouter`에 사용된 태그 이름과 동일한 `str`입니다.
* `description`: 태그에 대한 간단한 설명을 담은 `str`입니다. 마크다운을 사용할 수 있으며 문서 UI에 표시됩니다.
* `externalDocs`: 외부 문서를 설명하는 `dict`이며:
* `description`: 외부 문서에 대한 간단한 설명을 담은 `str`입니다.
* `url` (**필수**): 외부 문서의 URL을 담은 `str`입니다.
### 태그에 대한 메타데이터 생성
`users``items`에 대한 태그 예시와 함께 메타데이터를 생성하고 이를 `openapi_tags` 매개변수로 전달해 보겠습니다:
```Python hl_lines="3-16 18"
{!../../docs_src/metadata/tutorial004.py!}
```
설명 안에 마크다운을 사용할 수 있습니다. 예를 들어 "login"은 굵게(**login**) 표시되고, "fancy"는 기울임꼴(_fancy_)로 표시됩니다.
/// tip
사용 중인 모든 태그에 메타데이터를 추가할 필요는 없습니다.
///
### 태그 사용
`tags` 매개변수를 *경로 작동*`APIRouter`와 함께 사용하여 태그에 할당할 수 있습니다:
```Python hl_lines="21 26"
{!../../docs_src/metadata/tutorial004.py!}
```
/// info
태그에 대한 자세한 내용은 [경로 작동 구성](path-operation-configuration.md#tags){.internal-link target=_blank}에서 읽어보세요.
///
### 문서 확인
이제 문서를 확인하면 모든 추가 메타데이터가 표시됩니다:
<img src="/img/tutorial/metadata/image02.png">
### 태그 순서
각 태그 메타데이터 딕셔너리의 순서는 문서 UI에 표시되는 순서를 정의합니다.
예를 들어, 알파벳 순서상 `users``items` 뒤에 오지만, 우리는 `users` 메타데이터를 리스트의 첫 번째 딕셔너리로 추가했기 때문에 먼저 표시됩니다.
## OpenAPI URL
OpenAPI 구조는 기본적으로 `/openapi.json`에서 제공됩니다.
`openapi_url` 매개변수를 통해 이를 설정할 수 있습니다.
예를 들어, 이를 `/api/v1/openapi.json`에 제공하도록 설정하려면:
```Python hl_lines="3"
{!../../docs_src/metadata/tutorial002.py!}
```
OpenAPI 구조를 완전히 비활성화하려면 `openapi_url=None`으로 설정할 수 있으며, 이를 사용하여 문서화 사용자 인터페이스도 비활성화됩니다.
## 문서화 URL
포함된 두 가지 문서화 사용자 인터페이스를 설정할 수 있습니다:
* **Swagger UI**: `/docs`에서 제공됩니다.
* `docs_url` 매개변수로 URL을 설정할 수 있습니다.
* `docs_url=None`으로 설정하여 비활성화할 수 있습니다.
* **ReDoc**: `/redoc`에서 제공됩니다.
* `redoc_url` 매개변수로 URL을 설정할 수 있습니다.
* `redoc_url=None`으로 설정하여 비활성화할 수 있습니다.
예를 들어, Swagger UI를 `/documentation`에서 제공하고 ReDoc을 비활성화하려면:
```Python hl_lines="3"
{!../../docs_src/metadata/tutorial003.py!}
```

32
docs/pl/docs/tutorial/first-steps.md

@ -2,9 +2,7 @@
Najprostszy plik FastAPI może wyglądać tak:
```Python
{!../../docs_src/first_steps/tutorial001.py!}
```
{* ../../docs_src/first_steps/tutorial001.py *}
Skopiuj to do pliku `main.py`.
@ -133,9 +131,7 @@ Możesz go również użyć do automatycznego generowania kodu dla klientów, kt
### Krok 1: zaimportuj `FastAPI`
```Python hl_lines="1"
{!../../docs_src/first_steps/tutorial001.py!}
```
{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
`FastAPI` jest klasą, która zapewnia wszystkie funkcjonalności Twojego API.
@ -149,9 +145,7 @@ Oznacza to, że możesz korzystać ze wszystkich funkcjonalności <a href="https
### Krok 2: utwórz instancję `FastAPI`
```Python hl_lines="3"
{!../../docs_src/first_steps/tutorial001.py!}
```
{*../../docs_src/first_steps/tutorial001.py hl[3] *}
Zmienna `app` będzie tutaj "instancją" klasy `FastAPI`.
@ -171,9 +165,7 @@ $ uvicorn main:app --reload
Jeśli stworzysz swoją aplikację, np.:
```Python hl_lines="3"
{!../../docs_src/first_steps/tutorial002.py!}
```
{* ../../docs_src/first_steps/tutorial002.py hl[3] *}
I umieścisz to w pliku `main.py`, to będziesz mógł tak wywołać `uvicorn`:
@ -250,9 +242,7 @@ Będziemy je również nazywali "**operacjami**".
#### Zdefiniuj *dekorator operacji na ścieżce*
```Python hl_lines="6"
{!../../docs_src/first_steps/tutorial001.py!}
```
{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
`@app.get("/")` mówi **FastAPI** że funkcja poniżej odpowiada za obsługę żądań, które trafiają do:
@ -306,9 +296,7 @@ To jest nasza "**funkcja obsługująca ścieżkę**":
* **operacja**: to `get`.
* **funkcja**: to funkcja poniżej "dekoratora" (poniżej `@app.get("/")`).
```Python hl_lines="7"
{!../../docs_src/first_steps/tutorial001.py!}
```
{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
Jest to funkcja Python.
@ -320,9 +308,7 @@ W tym przypadku jest to funkcja "asynchroniczna".
Możesz również zdefiniować to jako normalną funkcję zamiast `async def`:
```Python hl_lines="7"
{!../../docs_src/first_steps/tutorial003.py!}
```
{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
/// note
@ -332,9 +318,7 @@ Jeśli nie znasz różnicy, sprawdź [Async: *"In a hurry?"*](../async.md#in-a-h
### Krok 5: zwróć zawartość
```Python hl_lines="8"
{!../../docs_src/first_steps/tutorial001.py!}
```
{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
Możesz zwrócić `dict`, `list`, pojedynczą wartość jako `str`, `int`, itp.

20
docs/pt/docs/advanced/behind-a-proxy.md

@ -18,9 +18,7 @@ Nesse caso, o caminho original `/app` seria servido em `/api/v1/app`.
Embora todo o seu código esteja escrito assumindo que existe apenas `/app`.
```Python hl_lines="6"
{!../../docs_src/behind_a_proxy/tutorial001.py!}
```
{* ../../docs_src/behind_a_proxy/tutorial001.py hl[6] *}
E o proxy estaria **"removendo"** o **prefixo do caminho** 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`.
@ -98,9 +96,7 @@ Você pode obter o `root_path` atual usado pela sua aplicação para cada solici
Aqui estamos incluindo ele na mensagem apenas para fins de demonstração.
```Python hl_lines="8"
{!../../docs_src/behind_a_proxy/tutorial001.py!}
```
{* ../../docs_src/behind_a_proxy/tutorial001.py hl[8] *}
Então, se você iniciar o Uvicorn com:
@ -127,9 +123,7 @@ A resposta seria algo como:
Alternativamente, 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:
```Python hl_lines="3"
{!../../docs_src/behind_a_proxy/tutorial002.py!}
```
{* ../../docs_src/behind_a_proxy/tutorial002.py hl[3] *}
Passar o `root_path`h para `FastAPI` seria o equivalente a passar a opção de linha de comando `--root-path` para Uvicorn ou Hypercorn.
@ -309,9 +303,7 @@ Se você passar uma lista personalizada de `servers` e houver um `root_path` (po
Por exemplo:
```Python hl_lines="4-7"
{!../../docs_src/behind_a_proxy/tutorial003.py!}
```
{* ../../docs_src/behind_a_proxy/tutorial003.py hl[4:7] *}
Gerará um OpenAPI schema como:
@ -358,9 +350,7 @@ A interface de documentação interagirá com o servidor que você selecionar.
Se 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`:
```Python hl_lines="9"
{!../../docs_src/behind_a_proxy/tutorial004.py!}
```
{* ../../docs_src/behind_a_proxy/tutorial004.py hl[9] *}
e então ele não será incluído no OpenAPI schema.

344
docs/pt/docs/advanced/custom-response.md

@ -0,0 +1,344 @@
# Resposta Personalizada - HTML, Stream, File e outras
Por padrão, o **FastAPI** irá retornar respostas utilizando `JSONResponse`.
Mas você pode sobrescrever esse comportamento utilizando `Response` diretamente, como visto em [Retornando uma Resposta Diretamente](response-directly.md){.internal-link target=_blank}.
Mas 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", no cabeçalho HTTP `Content-Type` como parte do esquema OpenAPI gerado).
Mas você também pode declarar a `Response` que você deseja utilizar (e.g. qualquer subclasse de `Response`), em um *decorador de operação de rota* utilizando o parâmetro `response_class`.
Os conteúdos que você retorna em sua *função de operador de rota* serão colocados dentro dessa `Response`.
E se a `Response` tiver um media type JSON (`application/json`), como é o caso com `JSONResponse` e `UJSONResponse`, os dados que você retornar serão automaticamente convertidos (e filtrados) com qualquer `response_model` do Pydantic que for declarado em sua *função de operador de rota*.
/// note | Nota
Se 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.
///
## Utilizando `ORJSONResponse`
Por exemplo, se você precisa bastante de performance, você pode instalar e utilizar o <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a> e definir a resposta para ser uma `ORJSONResponse`.
Importe a classe, ou subclasse, de `Response` que você deseja utilizar e declare ela no *decorador de operação de rota*.
Para respostas grandes, retornar uma `Response` diretamente é muito mais rápido que retornar um dicionário.
Isso ocorre por que, por padrão, o FastAPI irá verificar cada item dentro do dicionário e garantir que ele seja serializável para JSON, utilizando o mesmo[Codificador Compatível com JSON](../tutorial/encoder.md){.internal-link target=_blank} explicado no tutorial. Isso permite que você retorne **objetos abstratos**, como modelos do banco de dados, por exemplo.
Mas se você tem certeza que o conteúdo que você está retornando é **serializável com JSON**, você pode passá-lo diretamente para a classe de resposta e evitar o trabalho extra que o FastAPI teria ao passar o conteúdo pelo `jsonable_encoder` antes de passar para a classe de resposta.
```Python hl_lines="2 7"
{!../../docs_src/custom_response/tutorial001b.py!}
```
/// info | Informação
O parâmetro `response_class` também será usado para definir o "media type" da resposta.
Neste caso, o cabeçalho HTTP `Content-Type` irá ser definido como `application/json`.
E será documentado como tal no OpenAPI.
///
/// tip | Dica
A `ORJSONResponse` está disponível apenas no FastAPI, e não no Starlette.
///
## Resposta HTML
Para retornar uma resposta com HTML diretamente do **FastAPI**, utilize `HTMLResponse`.
* Importe `HTMLResponse`
* Passe `HTMLResponse` como o parâmetro de `response_class` do seu *decorador de operação de rota*.
```Python hl_lines="2 7"
{!../../docs_src/custom_response/tutorial002.py!}
```
/// info | Informação
O parâmetro `response_class` também será usado para definir o "media type" da resposta.
Neste caso, o cabeçalho HTTP `Content-Type` será definido como `text/html`.
E será documentado como tal no OpenAPI.
///
### Retornando uma `Response`
Como visto em [Retornando uma Resposta Diretamente](response-directly.md){.internal-link target=_blank}, você também pode sobrescrever a resposta diretamente na sua *operação de rota*, ao retornar ela.
O mesmo exemplo de antes, retornando uma `HTMLResponse`, poderia parecer com:
```Python hl_lines="2 7 19"
{!../../docs_src/custom_response/tutorial003.py!}
```
/// warning | Aviso
Uma `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.
///
/// info | Informação
Obviamente, o cabeçalho `Content-Type`, o código de status, etc, virão do objeto `Response` que você retornou.
///
### Documentar no OpenAPI e sobrescrever `Response`
Se 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`.
A `response_class` será usada apenas para documentar o OpenAPI da *operação de rota*, mas sua `Response` será usada como foi definida.
##### Retornando uma `HTMLResponse` diretamente
Por exemplo, poderia ser algo como:
```Python hl_lines="7 21 23"
{!../../docs_src/custom_response/tutorial004.py!}
```
Neste exemplo, a função `generate_html_response()` já cria e retorna uma `Response` em vez de retornar o HTML em uma `str`.
Ao retornar o resultado chamando `generate_html_response()`, você já está retornando uma `Response` que irá sobrescrever o comportamento padrão do **FastAPI**.
Mas se você passasse uma `HTMLResponse` em `response_class` também, o **FastAPI** saberia como documentar isso no OpenAPI e na documentação interativa como um HTML com `text/html`:
<img src="/img/tutorial/custom-response/image01.png">
## Respostas disponíveis
Aqui estão algumas dos tipos de resposta disponíveis.
Lembre-se que você pode utilizar `Response` para retornar qualquer outra coisa, ou até mesmo criar uma subclasse personalizada.
/// note | Detalhes Técnicos
Você também pode utilizar `from starlette.responses import HTMLResponse`.
O **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.
///
### `Response`
A classe principal de respostas, todas as outras respostas herdam dela.
Você pode retorná-la diretamente.
Ela aceita os seguintes parâmetros:
* `content` - Uma sequência de caracteres (`str`) ou `bytes`.
* `status_code` - Um código de status HTTP do tipo `int`.
* `headers` - Um dicionário `dict` de strings.
* `media_type` - Uma `str` informando o media type. E.g. `"text/html"`.
O 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.
```Python hl_lines="1 18"
{!../../docs_src/response_directly/tutorial002.py!}
```
### `HTMLResponse`
Usa algum texto ou sequência de bytes e retorna uma resposta HTML. Como você leu acima.
### `PlainTextResponse`
Usa algum texto ou sequência de bytes para retornar uma resposta de texto não formatado.
```Python hl_lines="2 7 9"
{!../../docs_src/custom_response/tutorial005.py!}
```
### `JSONResponse`
Pega alguns dados e retorna uma resposta com codificação `application/json`.
É a resposta padrão utilizada no **FastAPI**, como você leu acima.
### `ORJSONResponse`
Uma alternativa mais rápida de resposta JSON utilizando o <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>, como você leu acima.
/// info | Informação
Essa resposta requer a instalação do pacote `orjson`, com o comando `pip install orjson`, por exemplo.
///
### `UJSONResponse`
Uma alternativa de resposta JSON utilizando a biblioteca <a href="https://github.com/ultrajson/ultrajson" class="external-link" target="_blank">`ujson`</a>.
/// info | Informação
Essa resposta requer a instalação do pacote `ujson`, com o comando `pip install ujson`, por exemplo.
///
/// warning | Aviso
`ujson` é menos cauteloso que a implementação nativa do Python na forma que os casos especiais são tratados
///
```Python hl_lines="2 7"
{!../../docs_src/custom_response/tutorial001.py!}
```
/// tip | Dica
É possível que `ORJSONResponse` seja uma alternativa mais rápida.
///
### `RedirectResponse`
Retorna um redirecionamento HTTP. Utiliza o código de status 307 (Redirecionamento Temporário) por padrão.
Você pode retornar uma `RedirectResponse` diretamente:
```Python hl_lines="2 9"
{!../../docs_src/custom_response/tutorial006.py!}
```
---
Ou você pode utilizá-la no parâmetro `response_class`:
```Python hl_lines="2 7 9"
{!../../docs_src/custom_response/tutorial006b.py!}
```
Se você fizer isso, então você pode retornar a URL diretamente da sua *função de operação de rota*
Neste caso, o `status_code` utilizada será o padrão de `RedirectResponse`, que é `307`.
---
Você também pode utilizar o parâmetro `status_code` combinado com o parâmetro `response_class`:
```Python hl_lines="2 7 9"
{!../../docs_src/custom_response/tutorial006c.py!}
```
### `StreamingResponse`
Recebe uma gerador assíncrono ou um gerador/iterador comum e retorna o corpo da requisição continuamente (stream).
```Python hl_lines="2 14"
{!../../docs_src/custom_response/tutorial007.py!}
```
#### Utilizando `StreamingResponse` com objetos semelhantes a arquivos
Se você tiver um objeto semelhante a um arquivo (e.g. o objeto retornado por `open()`), você pode criar uma função geradora para iterar sobre esse objeto.
Dessa forma, você não precisa ler todo o arquivo na memória primeiro, e você pode passar essa função geradora para `StreamingResponse` e retorná-la.
Isso inclui muitas bibliotecas que interagem com armazenamento em nuvem, processamento de vídeos, entre outras.
```{ .python .annotate hl_lines="2 10-12 14" }
{!../../docs_src/custom_response/tutorial008.py!}
```
1. Essa é a função geradora. É definida como "função geradora" porque contém declarações `yield` nela.
2. Ao utilizar o bloco `with`, nós garantimos que o objeto semelhante a um arquivo é fechado após a função geradora ser finalizada. Isto é, após a resposta terminar de ser enivada.
3. Essa declaração `yield from` informa a função para iterar sobre essa coisa nomeada de `file_like`. E então, para cada parte iterada, fornece essa parte como se viesse dessa função geradora (`iterfile`).
Então, é uma função geradora que transfere o trabalho de "geração" para alguma outra coisa interna.
Fazendo dessa forma, podemos colocá-la em um bloco `with`, e assim garantir que o objeto semelhante a um arquivo é fechado quando a função termina.
/// tip | Dica
Perceba que aqui estamos utilizando o `open()` da biblioteca padrão que não suporta `async` e `await`, e declaramos a operação de rota com o `def` básico.
///
### `FileResponse`
Envia um arquivo de forma assíncrona e contínua (stream).
*
Recebe um conjunto de argumentos do construtor diferente dos outros tipos de resposta:
* `path` - O caminho do arquivo que será transmitido
* `headers` - quaisquer cabeçalhos que serão incluídos, como um dicionário.
* `media_type` - Uma string com o media type. Se não for definida, o media type é inferido a partir do nome ou caminho do arquivo.
* `filename` - Se for definido, é incluído no cabeçalho `Content-Disposition`.
Respostas de Arquivos incluem o tamanho do arquivo, data da última modificação e ETags apropriados, nos cabeçalhos `Content-Length`, `Last-Modified` e `ETag`, respectivamente.
```Python hl_lines="2 10"
{!../../docs_src/custom_response/tutorial009.py!}
```
Você também pode usar o parâmetro `response_class`:
```Python hl_lines="2 8 10"
{!../../docs_src/custom_response/tutorial009b.py!}
```
Nesse caso, você pode retornar o caminho do arquivo diretamente da sua *função de operação de rota*.
## Classe de resposta personalizada
Você pode criar sua própria classe de resposta, herdando de `Response` e usando essa nova classe.
Por exemplo, vamos supor que você queira utilizar o <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>, mas com algumas configurações personalizadas que não estão incluídas na classe `ORJSONResponse`.
Vamos supor também que você queira retornar um JSON indentado e formatado, então você quer utilizar a opção `orjson.OPT_INDENT_2` do orjson.
Você poderia criar uma classe `CustomORJSONResponse`. A principal coisa a ser feita é sobrecarregar o método render da classe Response, `Response.render(content)`, que retorna o conteúdo em bytes, para retornar o conteúdo que você deseja:
```Python hl_lines="9-14 17"
{!../../docs_src/custom_response/tutorial009c.py!}
```
Agora em vez de retornar:
```json
{"message": "Hello World"}
```
...essa resposta retornará:
```json
{
"message": "Hello World"
}
```
Obviamente, você provavelmente vai encontrar maneiras muito melhores de se aproveitar disso do que a formatação de JSON. 😉
## Classe de resposta padrão
Quando você criar uma instância da classe **FastAPI** ou um `APIRouter` você pode especificar qual classe de resposta utilizar por padrão.
O padrão que define isso é o `default_response_class`.
No exemplo abaixo, o **FastAPI** irá utilizar `ORJSONResponse` por padrão, em todas as *operações de rota*, em vez de `JSONResponse`.
```Python hl_lines="2 4"
{!../../docs_src/custom_response/tutorial010.py!}
```
/// tip | Dica
Você ainda pode substituir `response_class` em *operações de rota* como antes.
///
## Documentação adicional
Você também pode declarar o media type e muitos outros detalhes no OpenAPI utilizando `responses`: [Retornos Adicionais no OpenAPI](additional-responses.md){.internal-link target=_blank}.

96
docs/pt/docs/advanced/middleware.md

@ -0,0 +1,96 @@
# Middleware Avançado
No tutorial principal você leu como adicionar [Middleware Personalizado](../tutorial/middleware.md){.internal-link target=_blank} à sua aplicação.
E então você também leu como lidar com [CORS com o `CORSMiddleware`](../tutorial/cors.md){.internal-link target=_blank}.
Nesta seção, veremos como usar outros middlewares.
## Adicionando middlewares ASGI
Como o **FastAPI** é baseado no Starlette e implementa a especificação <abbr title="Asynchronous Server Gateway Interface">ASGI</abbr>, você pode usar qualquer middleware ASGI.
O middleware não precisa ser feito para o FastAPI ou Starlette para funcionar, desde que siga a especificação ASGI.
No geral, os middlewares ASGI são classes que esperam receber um aplicativo ASGI como o primeiro argumento.
Então, na documentação de middlewares ASGI de terceiros, eles provavelmente dirão para você fazer algo como:
```Python
from unicorn import UnicornMiddleware
app = SomeASGIApp()
new_app = UnicornMiddleware(app, some_config="rainbow")
```
Mas, 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.
Para isso, você usa `app.add_middleware()` (como no exemplo para CORS).
```Python
from fastapi import FastAPI
from unicorn import UnicornMiddleware
app = FastAPI()
app.add_middleware(UnicornMiddleware, some_config="rainbow")
```
`app.add_middleware()` recebe uma classe de middleware como o primeiro argumento e quaisquer argumentos adicionais a serem passados para o middleware.
## Middlewares Integrados
**FastAPI** inclui vários middlewares para casos de uso comuns, veremos a seguir como usá-los.
/// note | Detalhes Técnicos
Para o próximo exemplo, você também poderia usar `from starlette.middleware.something import SomethingMiddleware`.
**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.
///
## `HTTPSRedirectMiddleware`
Garante que todas as requisições devem ser `https` ou `wss`.
Qualquer requisição para `http` ou `ws` será redirecionada para o esquema seguro.
{* ../../docs_src/advanced_middleware/tutorial001.py hl[2,6] *}
## `TrustedHostMiddleware`
Garante 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.
{* ../../docs_src/advanced_middleware/tutorial002.py hl[2,6:8] *}
Os seguintes argumentos são suportados:
* `allowed_hosts` - Uma lista de nomes de domínio que são permitidos como nomes de host. Domínios com coringa, como `*.example.com`, são suportados para corresponder a subdomínios. Para permitir qualquer nome de host, use `allowed_hosts=["*"]` ou omita o middleware.
Se uma requisição recebida não for validada corretamente, uma resposta `400` será enviada.
## `GZipMiddleware`
Gerencia respostas GZip para qualquer requisição que inclua `"gzip"` no cabeçalho `Accept-Encoding`.
O middleware lidará com respostas padrão e de streaming.
{* ../../docs_src/advanced_middleware/tutorial003.py hl[2,6] *}
Os seguintes argumentos são suportados:
* `minimum_size` - Não comprima respostas menores que este tamanho mínimo em bytes. O padrão é `500`.
* `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.
## Outros middlewares
Há muitos outros middlewares ASGI.
Por exemplo:
* <a href="https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py" class="external-link" target="_blank">Uvicorn's `ProxyHeadersMiddleware`</a>
* <a href="https://github.com/florimondmanca/msgpack-asgi" class="external-link" target="_blank">MessagePack</a>
Para checar outros middlewares disponíveis, confira <a href="https://www.starlette.io/middleware/" class="external-link" target="_blank">Documentação de Middlewares do Starlette</a> e a <a href="https://github.com/florimondmanca/awesome-asgi" class="external-link" target="_blank">Lista Incrível do ASGI</a>.

194
docs/pt/docs/advanced/openapi-callbacks.md

@ -0,0 +1,194 @@
# Callbacks na OpenAPI
Você poderia criar uma API com uma *operação de rota* que poderia acionar uma solicitação a uma *API externa* criada por outra pessoa (provavelmente o mesmo desenvolvedor que estaria *usando* sua API).
O processo que acontece quando seu aplicativo de API chama a *API externa* é chamado de "callback". Porque o software que o desenvolvedor externo escreveu envia uma solicitação para sua API e então sua API *chama de volta*, enviando uma solicitação para uma *API externa* (que provavelmente foi criada pelo mesmo desenvolvedor).
Nesse 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.
## Um aplicativo com callbacks
Vamos ver tudo isso com um exemplo.
Imagine que você tem um aplicativo que permite criar faturas.
Essas faturas terão um `id`, `title` (opcional), `customer` e `total`.
O usuário da sua API (um desenvolvedor externo) criará uma fatura em sua API com uma solicitação POST.
Então sua API irá (vamos imaginar):
* Enviar uma solicitação de pagamento para o desenvolvedor externo.
* Coletar o dinheiro.
* Enviar a notificação de volta para o usuário da API (o desenvolvedor externo).
* Isso será feito enviando uma solicitação POST (de *sua API*) para alguma *API externa* fornecida por esse desenvolvedor externo (este é o "callback").
## O aplicativo **FastAPI** normal
Vamos primeiro ver como o aplicativo da API normal se pareceria antes de adicionar o callback.
Ele 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.
Essa parte é bastante normal, a maior parte do código provavelmente já é familiar para você:
```Python hl_lines="9-13 36-53"
{!../../docs_src/openapi_callbacks/tutorial001.py!}
```
/// tip | Dica
O parâmetro de consulta `callback_url` usa um tipo Pydantic <a href="https://docs.pydantic.dev/latest/api/networks/" class="external-link" target="_blank">Url</a>.
///
A única coisa nova é o argumento `callbacks=invoices_callback_router.routes` no decorador da *operação de rota*. Veremos o que é isso a seguir.
## Documentando o callback
O código real do callback dependerá muito do seu próprio aplicativo de API.
E provavelmente variará muito de um aplicativo para o outro.
Poderia ser apenas uma ou duas linhas de código, como:
```Python
callback_url = "https://example.com/api/v1/invoices/events/"
httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
```
Mas 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 da solicitação do callback, etc.
Entã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*.
A documentação aparecerá na interface do Swagger em `/docs` em sua API, e permitirá que os desenvolvedores externos saibam como construir a *API externa*.
Esse exemplo não implementa o callback em si (que poderia ser apenas uma linha de código), apenas a parte da documentação.
/// tip | Dica
O callback real é apenas uma solicitação HTTP.
Quando implementando o callback por você mesmo, você pode usar algo como <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a> ou <a href="https://requests.readthedocs.io/" class="external-link" target="_blank">Requisições</a>.
///
## Escrevendo o código de documentação do callback
Esse código não será executado em seu aplicativo, nós só precisamos dele para *documentar* como essa *API externa* deveria ser.
Mas, você já sabe como criar facilmente documentação automática para uma API com o **FastAPI**.
Entã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).
/// tip | Dica
Quando 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*.
Adotar temporariamente esse ponto de vista (do *desenvolvedor externo*) pode ajudar a sentir que é mais óbvio onde colocar os parâmetros, o modelo Pydantic para o corpo, para a resposta, etc. para essa *API externa*.
///
### Criar um `APIRouter` para o callback
Primeiramente crie um novo `APIRouter` que conterá um ou mais callbacks.
```Python hl_lines="3 25"
{!../../docs_src/openapi_callbacks/tutorial001.py!}
```
### Crie a *operação de rota* do callback
Para criar a *operação de rota* do callback, use o mesmo `APIRouter` que você criou acima.
Ele deve parecer exatamente como uma *operação de rota* normal do FastAPI:
* Ele provavelmente deveria ter uma declaração do corpo que deveria receber, por exemplo. `body: InvoiceEvent`.
* E também deveria ter uma declaração de um código de status de resposta, por exemplo. `response_model=InvoiceEventReceived`.
```Python hl_lines="16-18 21-22 28-32"
{!../../docs_src/openapi_callbacks/tutorial001.py!}
```
Há 2 diferenças principais de uma *operação de rota* normal:
* 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`.
* A *rota* pode conter uma <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">expressão OpenAPI 3</a> (veja mais abaixo) onde pode usar variáveis com parâmetros e partes da solicitação original enviada para *sua API*.
### A expressão do caminho do callback
A *rota* do callback pode ter uma <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">expressão OpenAPI 3</a> que pode conter partes da solicitação original enviada para *sua API*.
Nesse caso, é a `str`:
```Python
"{$callback_url}/invoices/{$request.body.id}"
```
Então, se o usuário da sua API (o desenvolvedor externo) enviar uma solicitação para *sua API* para:
```
https://yourapi.com/invoices/?callback_url=https://www.external.org/events
```
com um corpo JSON de:
```JSON
{
"id": "2expen51ve",
"customer": "Mr. Richie Rich",
"total": "9999"
}
```
então *sua API* processará a fatura e, em algum momento posterior, enviará uma solicitação de callback para o `callback_url` (a *API externa*):
```
https://www.external.org/events/invoices/2expen51ve
```
com um corpo JSON contendo algo como:
```JSON
{
"description": "Payment celebration",
"paid": true
}
```
e esperaria uma resposta daquela *API externa* com um corpo JSON como:
```JSON
{
"ok": true
}
```
/// tip | Dica
Perceba 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`).
///
### Adicionar o roteador de callback
Nesse ponto você tem a(s) *operação 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.
Agora use o parâmetro `callbacks` no decorador da *operação de rota de sua API* para passar o atributo `.routes` (que é na verdade apenas uma `list` de rotas/*operações de rota*) do roteador de callback que você criou acima:
```Python hl_lines="35"
{!../../docs_src/openapi_callbacks/tutorial001.py!}
```
/// tip | Dica
Perceba 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`.
///
### Verifique a documentação
Agora você pode iniciar seu aplicativo e ir para <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Você verá sua documentação incluindo uma seção "Callbacks" para sua *operação de rota* que mostra como a *API externa* deveria ser:
<img src="/img/tutorial/openapi-callbacks/image01.png">

188
docs/pt/docs/advanced/websockets.md

@ -0,0 +1,188 @@
# WebSockets
Você pode usar <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" class="external-link" target="_blank">WebSockets</a> com **FastAPI**.
## Instalando `WebSockets`
Garanta que você criou um [ambiente virtual](../virtual-environments.md){.internal-link target=_blank}, o ativou e instalou o `websockets`:
<div class="termy">
```console
$ pip install websockets
---> 100%
```
</div>
## Cliente WebSockets
### Em produção
Em seu sistema de produção, você provavelmente tem um frontend criado com um framework moderno como React, Vue.js ou Angular.
E para comunicar usando WebSockets com seu backend, você provavelmente usaria as utilidades do seu frontend.
Ou você pode ter um aplicativo móvel nativo que se comunica diretamente com seu backend WebSocket, em código nativo.
Ou você pode ter qualquer outra forma de comunicar com o endpoint WebSocket.
---
Mas para este exemplo, usaremos um documento HTML muito simples com algum JavaScript, tudo dentro de uma string longa.
Esse, é claro, não é o ideal e você não o usaria para produção.
Na produção, você teria uma das opções acima.
Mas é a maneira mais simples de focar no lado do servidor de WebSockets e ter um exemplo funcional:
```Python hl_lines="2 6-38 41-43"
{!../../docs_src/websockets/tutorial001.py!}
```
## Criando um `websocket`
Em sua aplicação **FastAPI**, crie um `websocket`:
{*../../docs_src/websockets/tutorial001.py hl[46:47]*}
/// note | Detalhes Técnicos
Você também poderia usar `from starlette.websockets import WebSocket`.
A **FastAPI** fornece o mesmo `WebSocket` diretamente apenas como uma conveniência para você, o desenvolvedor. Mas ele vem diretamente do Starlette.
///
## Aguardar por mensagens e enviar mensagens
Em sua rota WebSocket você pode esperar (`await`) por mensagens e enviar mensagens.
{*../../docs_src/websockets/tutorial001.py hl[48:52]*}
Você pode receber e enviar dados binários, de texto e JSON.
## Tente você mesmo
Se seu arquivo for nomeado `main.py`, execute sua aplicação com:
<div class="termy">
```console
$ fastapi dev main.py
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
Abra seu navegador em: <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
Você verá uma página simples como:
<img src="/img/tutorial/websockets/image01.png">
Você pode digitar mensagens na caixa de entrada e enviá-las:
<img src="/img/tutorial/websockets/image02.png">
E sua aplicação **FastAPI** com WebSockets responderá de volta:
<img src="/img/tutorial/websockets/image03.png">
Você pode enviar (e receber) muitas mensagens:
<img src="/img/tutorial/websockets/image04.png">
E todas elas usarão a mesma conexão WebSocket.
## Usando `Depends` e outros
Nos endpoints WebSocket você pode importar do `fastapi` e usar:
* `Depends`
* `Security`
* `Cookie`
* `Header`
* `Path`
* `Query`
Eles funcionam da mesma forma que para outros endpoints FastAPI/*operações de rota*:
{*../../docs_src/websockets/tutorial002_an_py310.py hl[68:69,82]*}
/// info | Informação
Como isso é um WebSocket, não faz muito sentido levantar uma `HTTPException`, em vez disso levantamos uma `WebSocketException`.
Você pode usar um código de fechamento dos <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" class="external-link" target="_blank">códigos válidos definidos na especificação</a>.
///
### Tente os WebSockets com dependências
Se seu arquivo for nomeado `main.py`, execute sua aplicação com:
<div class="termy">
```console
$ fastapi dev main.py
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
Abrar seu browser em: <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
Lá você pode definir:
* O "Item ID", usado na rota.
* O "Token" usado como um parâmetro de consulta.
/// tip | Dica
Perceba que a consulta `token` será manipulada por uma dependência.
///
Com isso você pode conectar o WebSocket e então enviar e receber mensagens:
<img src="/img/tutorial/websockets/image05.png">
## Lidando com desconexões e múltiplos clientes
Quando 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.
{*../../docs_src/websockets/tutorial003_py39.py hl[79:81]*}
Para testar:
* Abrar o aplicativo com várias abas do navegador.
* Escreva mensagens a partir delas.
* Então feche uma das abas.
Isso levantará a exceção `WebSocketDisconnect`, e todos os outros clientes receberão uma mensagem como:
```
Client #1596980209979 left the chat
```
/// tip | Dica
O app acima é um exemplo mínimo e simples para demonstrar como lidar e transmitir mensagens para várias conexões WebSocket.
Mas tenha em mente que, como tudo é manipulado na memória, em uma única lista, ele só funcionará enquanto o processo estiver em execução e só funcionará com um único processo.
Se você precisa de algo fácil de integrar com o FastAPI, mas que seja mais robusto, suportado por Redis, PostgreSQL ou outros, verifique o <a href="https://github.com/encode/broadcaster" class="external-link" target="_blank">encode/broadcaster</a>.
///
## Mais informações
Para aprender mais sobre as opções, verifique a documentação do Starlette para:
* <a href="https://www.starlette.io/websockets/" class="external-link" target="_blank">A classe `WebSocket`</a>.
* <a href="https://www.starlette.io/endpoints/#websocketendpoint" class="external-link" target="_blank">Manipulação de WebSockets baseada em classes</a>.

132
docs/pt/docs/tutorial/metadata.md

@ -0,0 +1,132 @@
# Metadados e Urls de Documentos
Você pode personalizar várias configurações de metadados na sua aplicação **FastAPI**.
## Metadados para API
Você pode definir os seguintes campos que são usados na especificação OpenAPI e nas interfaces automáticas de documentação da API:
| Parâmetro | Tipo | Descrição |
|------------|------|-------------|
| `title` | `str` | O título da API. |
| `summary` | `str` | Um breve resumo da API. <small>Disponível desde OpenAPI 3.1.0, FastAPI 0.99.0.</small> |
| `description` | `str` | Uma breve descrição da API. Pode usar Markdown. |
| `version` | `string` | A versão da API. Esta é a versão da sua aplicação, não do OpenAPI. Por exemplo, `2.5.0`. |
| `terms_of_service` | `str` | Uma URL para os Termos de Serviço da API. Se fornecido, deve ser uma URL. |
| `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> |
| `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 <a href="https://spdx.org/licenses/" class="external-link" target="_blank">SPDX</a> 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> |
Você pode defini-los da seguinte maneira:
```Python hl_lines="3-16 19-32"
{!../../docs_src/metadata/tutorial001.py!}
```
/// tip | Dica
Você pode escrever Markdown no campo `description` e ele será renderizado na saída.
///
Com essa configuração, a documentação automática da API se pareceria com:
<img src="/img/tutorial/metadata/image01.png">
## Identificador de Licença
Desde 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.
Por exemplo:
```Python hl_lines="31"
{!../../docs_src/metadata/tutorial001_1.py!}
```
## Metadados para tags
Você também pode adicionar metadados adicionais para as diferentes tags usadas para agrupar suas operações de rota com o parâmetro `openapi_tags`.
Ele recebe uma lista contendo um dicionário para cada tag.
Cada dicionário pode conter:
* `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.
* `description`: uma `str` com uma breve descrição da tag. Pode conter Markdown e será exibido na interface de documentação.
* `externalDocs`: um `dict` descrevendo a documentação externa com:
* `description`: uma `str` com uma breve descrição da documentação externa.
* `url` (**obrigatório**): uma `str` com a URL da documentação externa.
### Criar Metadados para tags
Vamos tentar isso em um exemplo com tags para `users` e `items`.
Crie metadados para suas tags e passe-os para o parâmetro `openapi_tags`:
```Python hl_lines="3-16 18"
{!../../docs_src/metadata/tutorial004.py!}
```
Observe 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_).
/// tip | Dica
Você não precisa adicionar metadados para todas as tags que você usa.
///
### Use suas tags
Use o parâmetro `tags` com suas *operações de rota* (e `APIRouter`s) para atribuí-los a diferentes tags:
```Python hl_lines="21 26"
{!../../docs_src/metadata/tutorial004.py!}
```
/// info | Informação
Leia mais sobre tags em [Configuração de Operação de Caminho](path-operation-configuration.md#tags){.internal-link target=_blank}.
///
### Cheque os documentos
Agora, se você verificar a documentação, ela exibirá todos os metadados adicionais:
<img src="/img/tutorial/metadata/image02.png">
### Ordem das tags
A ordem de cada dicionário de metadados de tag também define a ordem exibida na interface de documentação.
Por 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.
## URL da OpenAPI
Por padrão, o esquema OpenAPI é servido em `/openapi.json`.
Mas você pode configurá-lo com o parâmetro `openapi_url`.
Por exemplo, para defini-lo para ser servido em `/api/v1/openapi.json`:
```Python hl_lines="3"
{!../../docs_src/metadata/tutorial002.py!}
```
Se 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.
## URLs da Documentação
Você pode configurar as duas interfaces de documentação incluídas:
* **Swagger UI**: acessível em `/docs`.
* Você pode definir sua URL com o parâmetro `docs_url`.
* Você pode desativá-la definindo `docs_url=None`.
* **ReDoc**: acessível em `/redoc`.
* Você pode definir sua URL com o parâmetro `redoc_url`.
* Você pode desativá-la definindo `redoc_url=None`.
Por exemplo, para definir o Swagger UI para ser servido em `/documentation` e desativar o ReDoc:
```Python hl_lines="3"
{!../../docs_src/metadata/tutorial003.py!}
```

176
docs/pt/docs/tutorial/request-files.md

@ -0,0 +1,176 @@
# Arquivos de Requisição
Você pode definir arquivos para serem enviados pelo cliente usando `File`.
/// info | Informação
Para receber arquivos enviados, primeiro instale o <a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a>.
Garanta que você criou um [ambiente virtual](../virtual-environments.md){.internal-link target=_blank}, o ativou e então o instalou, por exemplo:
```console
$ pip install python-multipart
```
Isso é necessário, visto que os arquivos enviados são enviados como "dados de formulário".
///
## Importe `File`
Importe `File` e `UploadFile` de `fastapi`:
{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *}
## Definir Parâmetros `File`
Crie parâmetros de arquivo da mesma forma que você faria para `Body` ou `Form`:
{* ../../docs_src/request_files/tutorial001_an_py39.py hl[9] *}
/// info | Informação
`File` é uma classe que herda diretamente de `Form`.
Mas lembre-se que quando você importa `Query`, `Path`, `File` e outros de `fastapi`, eles são, na verdade, funções que retornam classes especiais.
///
/// tip | Dica
Para 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).
///
Os arquivos serão enviados como "dados de formulário".
Se 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`.
Mantenha em mente que isso significa que todo o conteúdo será armazenado na memória. Isso funcionará bem para arquivos pequenos.
Mas há muitos casos em que você pode se beneficiar do uso de `UploadFile`.
## Parâmetros de Arquivo com `UploadFile`
Defina um parâmetro de arquivo com um tipo de `UploadFile`:
{* ../../docs_src/request_files/tutorial001_an_py39.py hl[14] *}
Utilizar `UploadFile` tem várias vantagens sobre `bytes`:
* Você não precisa utilizar o `File()` no valor padrão do parâmetro.
* Ele utiliza um arquivo "spooled":
* Um arquivo armazenado na memória até um limite máximo de tamanho, e após passar esse limite, ele será armazenado no disco.
* Isso significa que funcionará bem para arquivos grandes como imagens, vídeos, binários grandes, etc., sem consumir toda a memória.
* Você pode receber metadados do arquivo enviado.
* Ele tem uma <a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> interface `assíncrona`.
* Ele expõe um objeto python <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a> que você pode passar diretamente para outras bibliotecas que esperam um objeto semelhante a um arquivo("file-like").
### `UploadFile`
`UploadFile` tem os seguintes atributos:
* `filename`: Uma `str` com o nome do arquivo original que foi enviado (por exemplo, `myimage.jpg`).
* `content_type`: Uma `str` com o tipo de conteúdo (tipo MIME / tipo de mídia) (por exemplo, `image/jpeg`).
* `file`: Um <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a> (um <a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> 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("file-like").
`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).
* `write(data)`: Escreve `data` (`str` ou `bytes`) no arquivo.
* `read(size)`: Lê `size` (`int`) bytes/caracteres do arquivo.
* `seek(offset)`: Vai para o byte na posição `offset` (`int`) no arquivo.
* Por exemplo, `await myfile.seek(0)` irá para o início do arquivo.
* Isso é especialmente útil se você executar `await myfile.read()` uma vez e precisar ler o conteúdo novamente.
* `close()`: Fecha o arquivo.
Como todos esses métodos são métodos `assíncronos`, você precisa "aguardar" por eles.
Por exemplo, dentro de uma função de *operação de rota* `assíncrona`, você pode obter o conteúdo com:
```Python
contents = await myfile.read()
```
Se você estiver dentro de uma função de *operação de rota* normal `def`, você pode acessar o `UploadFile.file` diretamente, por exemplo:
```Python
contents = myfile.file.read()
```
/// note | Detalhes Técnicos do `async`
Quando você usa os métodos `async`, o **FastAPI** executa os métodos de arquivo em um threadpool e aguarda por eles.
///
/// note | "Detalhes Técnicos do Starlette"
O `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.
///
## O que é "Form Data"
O 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.
**FastAPI** se certificará de ler esses dados do lugar certo, ao invés de JSON.
/// note | "Detalhes Técnicos"
Dados de formulários normalmente são codificados usando o "media type" (tipo de mídia) `application/x-www-form-urlencoded` quando não incluem arquivos.
Mas 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.
Se você quiser ler mais sobre essas codificações e campos de formulário, vá para a <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network">MDN</abbr> web docs para <code>POST</code></a>.
///
/// warning | Aviso
Você 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`.
Isso não é uma limitação do **FastAPI**, é parte do protocolo HTTP.
///
## Upload de Arquivo Opcional
Você pode tornar um arquivo opcional usando anotações de tipo padrão e definindo um valor padrão de `None`:
{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}
## `UploadFile` com Metadados Adicionais
Você também pode usar `File()` com `UploadFile`, por exemplo, para definir metadados adicionais:
{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *}
## Uploads de Múltiplos Arquivos
É possível realizar o upload de vários arquivos ao mesmo tempo.
Eles serão associados ao mesmo "campo de formulário" enviado usando "dados de formulário".
Para usar isso, declare uma lista de `bytes` ou `UploadFile`:
{* ../../docs_src/request_files/tutorial002_an_py39.py hl[10,15] *}
Você receberá, tal como declarado, uma `list` de `bytes` ou `UploadFile`.
/// note | "Detalhes Técnicos"
Você pode também pode usar `from starlette.responses import HTMLResponse`.
**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.
///
### Uploads de Múltiplos Arquivos com Metadados Adicionais
Da mesma forma de antes, você pode usar `File()` para definir parâmetros adicionais, mesmo para `UploadFile`:
{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *}
## Recapitulando
Utilize `File`, `bytes` e `UploadFile` para declarar arquivos a serem enviados na requisição, enviados como dados de formulário.

539
docs/pt/docs/tutorial/security/simple-oauth2.md

@ -0,0 +1,539 @@
# Simples OAuth2 com senha e Bearer
Agora vamos construir a partir do capítulo anterior e adicionar as partes que faltam para ter um fluxo de segurança completo.
## Pegue o `username` (nome de usuário) e `password` (senha)
É utilizado o utils de segurança da **FastAPI** para obter o `username` e a `password`.
OAuth2 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.
E a especificação diz que os campos devem ser nomeados assim. Portanto, `user-name` ou `email` não funcionariam.
Mas não se preocupe, você pode mostrá-lo como quiser aos usuários finais no frontend.
E seus modelos de banco de dados podem usar qualquer outro nome que você desejar.
Mas 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).
A 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).
### `scope`
A especificação também diz que o cliente pode enviar outro campo de formulário "`scope`" (Escopo).
O nome do campo do formulário é `scope` (no singular), mas na verdade é uma longa string com "escopos" separados por espaços.
Cada “scope” é apenas uma string (sem espaços).
Normalmente são usados para declarar permissões de segurança específicas, por exemplo:
* `users:read` ou `users:write` são exemplos comuns.
* `instagram_basic` é usado pelo Facebook e Instagram.
* `https://www.googleapis.com/auth/drive` é usado pelo Google.
/// info | Informação
No OAuth2, um "scope" é apenas uma string que declara uma permissão específica necessária.
Não importa se tem outros caracteres como `:` ou se é uma URL.
Esses detalhes são específicos da implementação.
Para OAuth2 são apenas strings.
///
## Código para conseguir o `username` e a `password`
Agora vamos usar os utilitários fornecidos pelo **FastAPI** para lidar com isso.
### `OAuth2PasswordRequestForm`
Primeiro, importe `OAuth2PasswordRequestForm` e use-o como uma dependência com `Depends` na *operação de rota* para `/token`:
//// tab | Python 3.10+
```Python hl_lines="4 78"
{!> ../../docs_src/security/tutorial003_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="4 78"
{!> ../../docs_src/security/tutorial003_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="4 79"
{!> ../../docs_src/security/tutorial003_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip | Dica
Prefira usar a versão `Annotated`, se possível.
///
```Python hl_lines="2 74"
{!> ../../docs_src/security/tutorial003_py310.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip | Dica
Prefira usar a versão `Annotated`, se possível.
///
```Python hl_lines="4 76"
{!> ../../docs_src/security/tutorial003.py!}
```
////
`OAuth2PasswordRequestForm` é uma dependência de classe que declara um corpo de formulário com:
* O `username`.
* A `password`.
* Um campo `scope` opcional como uma string grande, composta de strings separadas por espaços.
* Um `grant_type` (tipo de concessão) opcional.
/// tip | Dica
A especificação OAuth2 na verdade *requer* um campo `grant_type` com um valor fixo de `password`, mas `OAuth2PasswordRequestForm` não o impõe.
Se você precisar aplicá-lo, use `OAuth2PasswordRequestFormStrict` em vez de `OAuth2PasswordRequestForm`.
///
* Um `client_id` opcional (não precisamos dele em nosso exemplo).
* Um `client_secret` opcional (não precisamos dele em nosso exemplo).
/// info | Informação
O `OAuth2PasswordRequestForm` não é uma classe especial para **FastAPI** como é `OAuth2PasswordBearer`.
`OAuth2PasswordBearer` faz com que **FastAPI** saiba que é um esquema de segurança. Portanto, é adicionado dessa forma ao OpenAPI.
Mas `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.
Mas como é um caso de uso comum, ele é fornecido diretamente pelo **FastAPI**, apenas para facilitar.
///
### Use os dados do formulário
/// tip | Dica
A 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ão estamos usando `scopes` neste exemplo, mas a funcionalidade está disponível se você precisar.
///
Agora, obtenha os dados do usuário do banco de dados (falso), usando o `username` do campo do formulário.
Se não existir tal usuário, retornaremos um erro dizendo "Incorrect username or password" (Nome de usuário ou senha incorretos).
Para o erro, usamos a exceção `HTTPException`:
//// tab | Python 3.10+
```Python hl_lines="3 79-81"
{!> ../../docs_src/security/tutorial003_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="3 79-81"
{!> ../../docs_src/security/tutorial003_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="3 80-82"
{!> ../../docs_src/security/tutorial003_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip | Dica
Prefira usar a versão `Annotated`, se possível.
///
```Python hl_lines="1 75-77"
{!> ../../docs_src/security/tutorial003_py310.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip | Dica
Prefira usar a versão `Annotated`, se possível.
///
```Python hl_lines="3 77-79"
{!> ../../docs_src/security/tutorial003.py!}
```
////
### Confira a password (senha)
Neste ponto temos os dados do usuário do nosso banco de dados, mas não verificamos a senha.
Vamos colocar esses dados primeiro no modelo `UserInDB` do Pydantic.
Você nunca deve salvar senhas em texto simples, portanto, usaremos o sistema de hashing de senhas (falsas).
Se as senhas não corresponderem, retornaremos o mesmo erro.
#### Hashing de senha
"Hashing" significa: converter algum conteúdo (uma senha neste caso) em uma sequência de bytes (apenas uma string) que parece algo sem sentido.
Sempre que você passa exatamente o mesmo conteúdo (exatamente a mesma senha), você obtém exatamente a mesma sequência aleatória de caracteres.
Mas você não pode converter a sequência aleatória de caracteres de volta para a senha.
##### Porque usar hashing de senha
Se 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.
Assim, 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).
//// tab | Python 3.10+
```Python hl_lines="82-85"
{!> ../../docs_src/security/tutorial003_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="82-85"
{!> ../../docs_src/security/tutorial003_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="83-86"
{!> ../../docs_src/security/tutorial003_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip | Dica
Prefira usar a versão `Annotated`, se possível.
///
```Python hl_lines="78-81"
{!> ../../docs_src/security/tutorial003_py310.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip | Dica
Prefira usar a versão `Annotated`, se possível.
///
```Python hl_lines="80-83"
{!> ../../docs_src/security/tutorial003.py!}
```
////
#### Sobre `**user_dict`
`UserInDB(**user_dict)` significa:
*Passe as keys (chaves) e values (valores) de `user_dict` diretamente como argumentos de valor-chave, equivalente a:*
```Python
UserInDB(
username = user_dict["username"],
email = user_dict["email"],
full_name = user_dict["full_name"],
disabled = user_dict["disabled"],
hashed_password = user_dict["hashed_password"],
)
```
/// info | Informação
Para uma explicação mais completa de `**user_dict`, verifique [a documentação para **Extra Models**](../extra-models.md#about-user_indict){.internal-link target=_blank}.
///
## Retorne o token
A resposta do endpoint `token` deve ser um objeto JSON.
Deve ter um `token_type`. No nosso caso, como estamos usando tokens "Bearer", o tipo de token deve ser "`bearer`".
E deve ter um `access_token`, com uma string contendo nosso token de acesso.
Para este exemplo simples, seremos completamente inseguros e retornaremos o mesmo `username` do token.
/// tip | Dica
No próximo capítulo, você verá uma implementação realmente segura, com hash de senha e tokens <abbr title="JSON Web Tokens">JWT</abbr>.
Mas, por enquanto, vamos nos concentrar nos detalhes específicos de que precisamos.
///
//// tab | Python 3.10+
```Python hl_lines="87"
{!> ../../docs_src/security/tutorial003_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="87"
{!> ../../docs_src/security/tutorial003_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="88"
{!> ../../docs_src/security/tutorial003_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip | Dica
Prefira usar a versão `Annotated`, se possível.
///
```Python hl_lines="83"
{!> ../../docs_src/security/tutorial003_py310.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip | Dica
Prefira usar a versão `Annotated`, se possível.
///
```Python hl_lines="85"
{!> ../../docs_src/security/tutorial003.py!}
```
////
/// tip | Dica
Pela especificação, você deve retornar um JSON com um `access_token` e um `token_type`, o mesmo que neste exemplo.
Isso é algo que você mesmo deve fazer em seu código e certifique-se de usar essas chaves JSON.
É quase a única coisa que você deve se lembrar de fazer corretamente, para estar em conformidade com as especificações.
De resto, **FastAPI** cuida disso para você.
///
## Atualize as dependências
Agora vamos atualizar nossas dependências.
Queremos obter o `user_user` *somente* se este usuário estiver ativo.
Portanto, criamos uma dependência adicional `get_current_active_user` que por sua vez usa `get_current_user` como dependência.
Ambas as dependências retornarão apenas um erro HTTP se o usuário não existir ou se estiver inativo.
Portanto, em nosso endpoint, só obteremos um usuário se o usuário existir, tiver sido autenticado corretamente e estiver ativo:
//// tab | Python 3.10+
```Python hl_lines="58-66 69-74 94"
{!> ../../docs_src/security/tutorial003_an_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="58-66 69-74 94"
{!> ../../docs_src/security/tutorial003_an_py39.py!}
```
////
//// tab | Python 3.8+
```Python hl_lines="59-67 70-75 95"
{!> ../../docs_src/security/tutorial003_an.py!}
```
////
//// tab | Python 3.10+ non-Annotated
/// tip | Dica
Prefira usar a versão `Annotated`, se possível.
///
```Python hl_lines="56-64 67-70 88"
{!> ../../docs_src/security/tutorial003_py310.py!}
```
////
//// tab | Python 3.8+ non-Annotated
/// tip | Dica
Prefira usar a versão `Annotated`, se possível.
///
```Python hl_lines="58-66 69-72 90"
{!> ../../docs_src/security/tutorial003.py!}
```
////
/// info | Informação
O cabeçalho adicional `WWW-Authenticate` com valor `Bearer` que estamos retornando aqui também faz parte da especificação.
Qualquer código de status HTTP (erro) 401 "UNAUTHORIZED" também deve retornar um cabeçalho `WWW-Authenticate`.
No caso de tokens ao portador (nosso caso), o valor desse cabeçalho deve ser `Bearer`.
Na verdade, você pode pular esse cabeçalho extra e ainda funcionaria.
Mas é fornecido aqui para estar em conformidade com as especificações.
Alé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.
Esse é o benefício dos padrões...
///
## Veja em ação
Abra o docs interativo: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
### Autenticação
Clique no botão "Authorize".
Use as credenciais:
User: `johndoe`
Password: `secret`
<img src="/img/tutorial/security/image04.png">
Após autenticar no sistema, você verá assim:
<img src="/img/tutorial/security/image05.png">
### Obtenha seus próprios dados de usuário
Agora use a operação `GET` com o caminho `/users/me`.
Você obterá os dados do seu usuário, como:
```JSON
{
"username": "johndoe",
"email": "johndoe@example.com",
"full_name": "John Doe",
"disabled": false,
"hashed_password": "fakehashedsecret"
}
```
<img src="/img/tutorial/security/image06.png">
Se você clicar no ícone de cadeado, sair e tentar a mesma operação novamente, receberá um erro HTTP 401 de:
```JSON
{
"detail": "Not authenticated"
}
```
### Usuário inativo
Agora tente com um usuário inativo, autentique-se com:
User: `alice`
Password: `secret2`
E tente usar a operação `GET` com o caminho `/users/me`.
Você receberá um erro "Usuário inativo", como:
```JSON
{
"detail": "Inactive user"
}
```
## Recaptulando
Agora você tem as ferramentas para implementar um sistema de segurança completo baseado em `username` e `password` para sua API.
Usando 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.
O único detalhe que falta é que ainda não é realmente "seguro".
No próximo capítulo você verá como usar uma biblioteca de hashing de senha segura e tokens <abbr title="JSON Web Tokens">JWT</abbr>.

359
docs/pt/docs/tutorial/sql-databases.md

@ -0,0 +1,359 @@
# Bancos de Dados SQL (Relacionais)
**FastAPI** não exige que você use um banco de dados SQL (relacional). Mas você pode usar **qualquer banco de dados** que quiser.
Aqui veremos um exemplo usando <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">SQLModel</a>.
**SQLModel** é construído sobre <a href="https://www.sqlalchemy.org/" class="external-link" target="_blank">SQLAlchemy</a> 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**.
/// tip | Dica
Você pode usar qualquer outra biblioteca de banco de dados SQL ou NoSQL que quiser (em alguns casos chamadas de <abbr title="Object Relational Mapper, 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. 😎
///
Como 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:
* PostgreSQL
* MySQL
* SQLite
* Oracle
* Microsoft SQL Server, etc.
Neste 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á.
Mais tarde, para sua aplicação em produção, você pode querer usar um servidor de banco de dados como o **PostgreSQL**.
/// tip | Dica
Existe um gerador de projetos oficial com **FastAPI** e **PostgreSQL** incluindo um frontend e mais ferramentas: <a href="https://github.com/fastapi/full-stack-fastapi-template" class="external-link" target="_blank">https://github.com/fastapi/full-stack-fastapi-template</a>
///
Este é 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 <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">documentação do SQLModel</a>.
## Instalar o `SQLModel`
Primeiro, certifique-se de criar seu [ambiente virtual](../virtual-environments.md){.internal-link target=_blank}, ativá-lo e, em seguida, instalar o `sqlmodel`:
<div class="termy">
```console
$ pip install sqlmodel
---> 100%
```
</div>
## Criar o App com um Único Modelo
Vamos criar a primeira versão mais simples do app com um único modelo **SQLModel**.
Depois, vamos melhorá-lo aumentando a segurança e versatilidade com **múltiplos modelos** abaixo. 🤓
### Criar Modelos
Importe o `SQLModel` e crie um modelo de banco de dados:
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}
A classe `Hero` é muito semelhante a um modelo Pydantic (na verdade, por baixo dos panos, ela *é um modelo Pydantic*).
Existem algumas diferenças:
* `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).
* `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).
Ao ter o tipo como `int | None`, o SQLModel saberá que essa coluna deve ser um `INTEGER` no banco de dados SQL e que ela deve ser `NULLABLE`.
* `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.
O SQLModel saberá que algo declarado como `str` será uma coluna SQL do tipo `TEXT` (ou `VARCHAR`, dependendo do banco de dados).
### Criar um Engine
Um `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.
Você teria **um único objeto `engine`** para todo o seu código se conectar ao mesmo banco de dados.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}
Usar `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ã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.
### Criar as Tabelas
Em seguida, adicionamos uma função que usa `SQLModel.metadata.create_all(engine)` para **criar as tabelas** para todos os *modelos de tabela*.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}
### Criar uma Dependência de Sessão
Uma **`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.
Vamos 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. 🤓
Então, criamos uma dependência `Annotated` chamada `SessionDep` para simplificar o restante do código que usará essa dependência.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30] hl[25:27,30] *}
### Criar Tabelas de Banco de Dados na Inicialização
Vamos criar as tabelas do banco de dados quando o aplicativo for iniciado.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}
Aqui, criamos as tabelas em um evento de inicialização do aplicativo.
Para produção, você provavelmente usaria um script de migração que é executado antes de iniciar seu app. 🤓
/// tip | Dica
O SQLModel terá utilitários de migração envolvendo o Alembic, mas por enquanto, você pode usar o <a href="https://alembic.sqlalchemy.org/en/latest/" class="external-link" target="_blank">Alembic</a> diretamente.
///
### Criar um Hero
Como cada modelo SQLModel também é um modelo Pydantic, você pode usá-lo nas mesmas **anotações de tipo** que usaria para modelos Pydantic.
Por exemplo, se você declarar um parâmetro do tipo `Hero`, ele será lido do **corpo JSON**.
Da 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.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}
</details>
Aqui, 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.
### Ler Heroes
Podemos **ler** `Hero`s do banco de dados usando um `select()`. Podemos incluir um `limit` e `offset` para paginar os resultados.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}
### Ler um Único Hero
Podemos **ler** um único `Hero`.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}
### Deletar um Hero
Também podemos **deletar** um `Hero`.
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}
### Executar o App
Você pode executar o app:
<div class="termy">
```console
$ fastapi dev main.py
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
Entã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.
<div class="screenshot">
<img src="/img/tutorial/sql-databases/image01.png">
</div>
## Atualizar o App com Múltiplos Modelos
Agora vamos **refatorar** este app um pouco para aumentar a **segurança** e **versatilidade**.
Se você verificar o app anterior, na interface você pode ver que, até agora, ele permite que o cliente decida o `id` do `Hero` a ser criado. 😱
Nã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**.
Além disso, criamos um `secret_name` para o hero, mas até agora estamos retornando ele em todos os lugares, isso não é muito **secreto**... 😅
Vamos corrigir essas coisas adicionando alguns **modelos extras**. Aqui é onde o SQLModel vai brilhar. ✨
### Criar Múltiplos Modelos
No **SQLModel**, qualquer classe de modelo que tenha `table=True` é um **modelo de tabela**.
E 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). 🤓
Com o SQLModel, podemos usar a **herança** para **evitar duplicação** de todos os campos em todos os casos.
#### `HeroBase` - a classe base
Vamos começar com um modelo `HeroBase` que tem todos os **campos compartilhados** por todos os modelos:
* `name`
* `age`
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}
#### `Hero` - o *modelo de tabela*
Em seguida, vamos criar `Hero`, o verdadeiro *modelo de tabela*, com os **campos extras** que nem sempre estão nos outros modelos:
* `id`
* `secret_name`
Como `Hero` herda de `HeroBase`, ele **também** tem os **campos** declarados em `HeroBase`, então todos os campos para `Hero` são:
* `id`
* `name`
* `age`
* `secret_name`
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}
#### `HeroPublic` - o *modelo de dados* público
Em seguida, criamos um modelo `HeroPublic`, que será **retornado** para os clientes da API.
Ele tem os mesmos campos que `HeroBase`, então não incluirá `secret_name`.
Finalmente, a identidade dos nossos heróis está protegida! 🥷
Ele 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`).
/// tip | Dica
Fazer 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.
Alé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. 😎
///
Todos os campos em `HeroPublic` são os mesmos que em `HeroBase`, com `id` declarado como `int` (não `None`):
* `id`
* `name`
* `age`
* `secret_name`
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}
#### `HeroCreate` - o *modelo de dados* para criar um hero
Agora criamos um modelo `HeroCreate`, este é o que **validará** os dados dos clientes.
Ele tem os mesmos campos que `HeroBase`, e também tem `secret_name`.
Agora, 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.
/// tip | Dica
É assim que você trataria **senhas**. Receba-as, mas não as retorne na API.
Você também faria um **hash** com os valores das senhas antes de armazená-los, **nunca os armazene em texto simples**.
///
Os campos de `HeroCreate` são:
* `name`
* `age`
* `secret_name`
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}
#### `HeroUpdate` - o *modelo de dados* para atualizar um hero
Não tínhamos uma maneira de **atualizar um hero** na versão anterior do app, mas agora com **múltiplos modelos**, podemos fazer isso. 🎉
O *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.
Como 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ã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. 🤷
Os campos de `HeroUpdate` são:
* `name`
* `age`
* `secret_name`
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}
### Criar com `HeroCreate` e retornar um `HeroPublic`
Agora que temos **múltiplos modelos**, podemos atualizar as partes do app que os utilizam.
Recebemos na requisição um *modelo de dados* `HeroCreate`, e a partir dele, criamos um *modelo de tabela* `Hero`.
Esse novo *modelo de tabela* `Hero` terá os campos enviados pelo cliente, e também terá um `id` gerado pelo banco de dados.
Em 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.
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}
/// tip | Dica
Agora 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`.
Se tivéssemos declarado `-> HeroPublic`, seu editor e o linter reclamariam (com razão) que você está retornando um `Hero` em vez de um `HeroPublic`.
Ao 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.
///
### Ler Heroes com `HeroPublic`
Podemos 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.
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}
### Ler Um Hero com `HeroPublic`
Podemos **ler** um único herói:
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}
### Atualizar um Hero com `HeroUpdate`
Podemos **atualizar um hero**. Para isso, usamos uma operação HTTP `PATCH`.
E 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. 🪄
Em seguida, usamos `hero_db.sqlmodel_update(hero_data)` para atualizar o `hero_db` com os dados de `hero_data`.
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}
### Deletar um Hero Novamente
**Deletar** um hero permanece praticamente o mesmo.
Não vamos satisfazer o desejo de refatorar tudo neste aqui. 😅
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}
### Executar o App Novamente
Você pode executar o app novamente:
<div class="termy">
```console
$ fastapi dev main.py
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
If 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.
<div class="screenshot">
<img src="/img/tutorial/sql-databases/image02.png">
</div>
## Recapitulando
Você pode usar <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">**SQLModel**</a> para interagir com um banco de dados SQL e simplificar o código com *modelos de dados* e *modelos de tabela*.
Você pode aprender muito mais na documentação do **SQLModel**, há um mini <a href="https://sqlmodel.tiangolo.com/tutorial/fastapi/" class="external-link" target="_blank">tutorial sobre como usar SQLModel com **FastAPI**</a> mais longo. 🚀

2
fastapi/__init__.py

@ -1,6 +1,6 @@
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
__version__ = "0.115.3"
__version__ = "0.115.4"
from starlette import status as status

30
fastapi/dependencies/utils.py

@ -90,21 +90,29 @@ multipart_incorrect_install_error = (
def ensure_multipart_is_installed() -> None:
try:
# __version__ is available in both multiparts, and can be mocked
from multipart import __version__
from python_multipart import __version__
assert __version__
# Import an attribute that can be mocked/deleted in testing
assert __version__ > "0.0.12"
except (ImportError, AssertionError):
try:
# parse_options_header is only available in the right multipart
from multipart.multipart import parse_options_header
# __version__ is available in both multiparts, and can be mocked
from multipart import __version__ # type: ignore[no-redef,import-untyped]
assert parse_options_header # type: ignore[truthy-function]
assert __version__
try:
# parse_options_header is only available in the right multipart
from multipart.multipart import ( # type: ignore[import-untyped]
parse_options_header,
)
assert parse_options_header
except ImportError:
logger.error(multipart_incorrect_install_error)
raise RuntimeError(multipart_incorrect_install_error) from None
except ImportError:
logger.error(multipart_incorrect_install_error)
raise RuntimeError(multipart_incorrect_install_error) from None
except ImportError:
logger.error(multipart_not_installed_error)
raise RuntimeError(multipart_not_installed_error) from None
logger.error(multipart_not_installed_error)
raise RuntimeError(multipart_not_installed_error) from None
def get_param_sub_dependant(

4
requirements-docs.txt

@ -3,12 +3,12 @@
mkdocs-material==9.5.18
mdx-include >=1.4.1,<2.0.0
mkdocs-redirects>=1.2.1,<1.3.0
typer == 0.12.3
typer == 0.12.5
pyyaml >=5.3.1,<7.0.0
# For Material for MkDocs, Chinese search
jieba==0.42.1
# For image processing by Material for MkDocs
pillow==10.4.0
pillow==11.0.0
# For image processing by Material for MkDocs
cairosvg==2.7.1
mkdocstrings[python]==0.26.1

4
requirements-tests.txt

@ -1,11 +1,11 @@
-e .[all]
-r requirements-docs-tests.txt
pytest >=7.1.3,<8.0.0
pytest >=7.1.3,<9.0.0
coverage[toml] >= 6.5.0,< 8.0
mypy ==1.8.0
dirty-equals ==0.6.0
sqlmodel==0.0.22
flask >=1.1.2,<3.0.0
flask >=1.1.2,<4.0.0
anyio[trio] >=3.2.1,<4.0.0
PyJWT==2.8.0
pyyaml >=5.3.1,<7.0.0

2
requirements.txt

@ -1,6 +1,6 @@
-e .[all]
-r requirements-tests.txt
-r requirements-docs.txt
pre-commit >=2.17.0,<4.0.0
pre-commit >=2.17.0,<5.0.0
# For generating screenshots
playwright

107
tests/test_multipart_installation.py

@ -1,3 +1,5 @@
import warnings
import pytest
from fastapi import FastAPI, File, Form, UploadFile
from fastapi.dependencies.utils import (
@ -7,7 +9,10 @@ from fastapi.dependencies.utils import (
def test_incorrect_multipart_installed_form(monkeypatch):
monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
monkeypatch.setattr("python_multipart.__version__", "0.0.12")
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
with pytest.raises(RuntimeError, match=multipart_incorrect_install_error):
app = FastAPI()
@ -17,7 +22,10 @@ def test_incorrect_multipart_installed_form(monkeypatch):
def test_incorrect_multipart_installed_file_upload(monkeypatch):
monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
monkeypatch.setattr("python_multipart.__version__", "0.0.12")
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
with pytest.raises(RuntimeError, match=multipart_incorrect_install_error):
app = FastAPI()
@ -27,7 +35,10 @@ def test_incorrect_multipart_installed_file_upload(monkeypatch):
def test_incorrect_multipart_installed_file_bytes(monkeypatch):
monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
monkeypatch.setattr("python_multipart.__version__", "0.0.12")
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
with pytest.raises(RuntimeError, match=multipart_incorrect_install_error):
app = FastAPI()
@ -37,7 +48,10 @@ def test_incorrect_multipart_installed_file_bytes(monkeypatch):
def test_incorrect_multipart_installed_multi_form(monkeypatch):
monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
monkeypatch.setattr("python_multipart.__version__", "0.0.12")
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
with pytest.raises(RuntimeError, match=multipart_incorrect_install_error):
app = FastAPI()
@ -47,7 +61,10 @@ def test_incorrect_multipart_installed_multi_form(monkeypatch):
def test_incorrect_multipart_installed_form_file(monkeypatch):
monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
monkeypatch.setattr("python_multipart.__version__", "0.0.12")
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
monkeypatch.delattr("multipart.multipart.parse_options_header", raising=False)
with pytest.raises(RuntimeError, match=multipart_incorrect_install_error):
app = FastAPI()
@ -57,50 +74,76 @@ def test_incorrect_multipart_installed_form_file(monkeypatch):
def test_no_multipart_installed(monkeypatch):
monkeypatch.delattr("multipart.__version__", raising=False)
with pytest.raises(RuntimeError, match=multipart_not_installed_error):
app = FastAPI()
monkeypatch.setattr("python_multipart.__version__", "0.0.12")
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
monkeypatch.delattr("multipart.__version__", raising=False)
with pytest.raises(RuntimeError, match=multipart_not_installed_error):
app = FastAPI()
@app.post("/")
async def root(username: str = Form()):
return username # pragma: nocover
@app.post("/")
async def root(username: str = Form()):
return username # pragma: nocover
def test_no_multipart_installed_file(monkeypatch):
monkeypatch.delattr("multipart.__version__", raising=False)
with pytest.raises(RuntimeError, match=multipart_not_installed_error):
app = FastAPI()
monkeypatch.setattr("python_multipart.__version__", "0.0.12")
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
monkeypatch.delattr("multipart.__version__", raising=False)
with pytest.raises(RuntimeError, match=multipart_not_installed_error):
app = FastAPI()
@app.post("/")
async def root(f: UploadFile = File()):
return f # pragma: nocover
@app.post("/")
async def root(f: UploadFile = File()):
return f # pragma: nocover
def test_no_multipart_installed_file_bytes(monkeypatch):
monkeypatch.delattr("multipart.__version__", raising=False)
with pytest.raises(RuntimeError, match=multipart_not_installed_error):
app = FastAPI()
monkeypatch.setattr("python_multipart.__version__", "0.0.12")
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
monkeypatch.delattr("multipart.__version__", raising=False)
with pytest.raises(RuntimeError, match=multipart_not_installed_error):
app = FastAPI()
@app.post("/")
async def root(f: bytes = File()):
return f # pragma: nocover
@app.post("/")
async def root(f: bytes = File()):
return f # pragma: nocover
def test_no_multipart_installed_multi_form(monkeypatch):
monkeypatch.delattr("multipart.__version__", raising=False)
with pytest.raises(RuntimeError, match=multipart_not_installed_error):
app = FastAPI()
monkeypatch.setattr("python_multipart.__version__", "0.0.12")
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
monkeypatch.delattr("multipart.__version__", raising=False)
with pytest.raises(RuntimeError, match=multipart_not_installed_error):
app = FastAPI()
@app.post("/")
async def root(username: str = Form(), password: str = Form()):
return username # pragma: nocover
@app.post("/")
async def root(username: str = Form(), password: str = Form()):
return username # pragma: nocover
def test_no_multipart_installed_form_file(monkeypatch):
monkeypatch.delattr("multipart.__version__", raising=False)
with pytest.raises(RuntimeError, match=multipart_not_installed_error):
monkeypatch.setattr("python_multipart.__version__", "0.0.12")
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
monkeypatch.delattr("multipart.__version__", raising=False)
with pytest.raises(RuntimeError, match=multipart_not_installed_error):
app = FastAPI()
@app.post("/")
async def root(username: str = Form(), f: UploadFile = File()):
return username # pragma: nocover
def test_old_multipart_installed(monkeypatch):
monkeypatch.setattr("python_multipart.__version__", "0.0.12")
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
app = FastAPI()
@app.post("/")
async def root(username: str = Form(), f: UploadFile = File()):
async def root(username: str = Form()):
return username # pragma: nocover

Loading…
Cancel
Save