mirror of https://github.com/tiangolo/fastapi.git
Merge branch 'master' into deferred-init
This commit is contained in:
commit
42ea3b22c4
|
|
@ -62,7 +62,10 @@ jobs:
|
|||
env:
|
||||
PROJECT_NAME: fastapitiangolo
|
||||
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 ) }}
|
||||
uses: cloudflare/wrangler-action@v3
|
||||
# TODO: Use v3 when it's fixed, probably in v3.11
|
||||
# https://github.com/cloudflare/wrangler-action/issues/307
|
||||
uses: cloudflare/wrangler-action@v3.11
|
||||
# uses: cloudflare/wrangler-action@v3
|
||||
with:
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ repos:
|
|||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.6.9
|
||||
rev: v0.7.0
|
||||
hooks:
|
||||
- id: ruff
|
||||
args:
|
||||
|
|
|
|||
|
|
@ -339,6 +339,10 @@ Articles:
|
|||
link: https://qiita.com/mtitg/items/47770e9a562dd150631d
|
||||
title: FastAPI|DB接続してCRUDするPython製APIサーバーを構築
|
||||
Portuguese:
|
||||
- author: Eduardo Mendes
|
||||
author_link: https://bolha.us/@dunossauro
|
||||
link: https://fastapidozero.dunossauro.com/
|
||||
title: FastAPI do ZERO
|
||||
- author: Jessica Temporal
|
||||
author_link: https://jtemporal.com/socials
|
||||
link: https://jtemporal.com/dicas-para-migrar-de-flask-para-fastapi-e-vice-versa/
|
||||
|
|
|
|||
|
|
@ -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] *}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,38 @@ hide:
|
|||
|
||||
## Latest Changes
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 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
|
||||
|
||||
* 🌐 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).
|
||||
* 🌐 Update Traditional Chinese translation for `docs/zh-hant/docs/how-to/index.md`. PR [#12523](https://github.com/fastapi/fastapi/pull/12523) by [@codingjenny](https://github.com/codingjenny).
|
||||
* 🌐 Update Traditional Chinese translation for `docs/zh-hant/docs/tutorial/index.md`. PR [#12524](https://github.com/fastapi/fastapi/pull/12524) by [@codingjenny](https://github.com/codingjenny).
|
||||
* 🌐 Add Traditional Chinese translation for `docs/zh-hant/docs/how-to/index.md`. PR [#12468](https://github.com/fastapi/fastapi/pull/12468) by [@codingjenny](https://github.com/codingjenny).
|
||||
* 🌐 Add Traditional Chinese translation for `docs/zh-hant/docs/tutorial/index.md`. PR [#12466](https://github.com/fastapi/fastapi/pull/12466) by [@codingjenny](https://github.com/codingjenny).
|
||||
* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/header-param-models.md`. PR [#12437](https://github.com/fastapi/fastapi/pull/12437) by [@Joao-Pedro-P-Holanda](https://github.com/Joao-Pedro-P-Holanda).
|
||||
* 🌐 Add Portuguese translation for `docs/pt/docs/how-to/extending-openapi.md`. PR [#12470](https://github.com/fastapi/fastapi/pull/12470) by [@ilacftemp](https://github.com/ilacftemp).
|
||||
* 🌐 Add Portuguese translation for `docs/pt/docs/advanced/dataclasses.md`. PR [#12475](https://github.com/fastapi/fastapi/pull/12475) by [@leoscarlato](https://github.com/leoscarlato).
|
||||
* 🌐 Add Portuguese translation for `docs/pt/docs/how-to/custom-request-and-route.md`. PR [#12483](https://github.com/fastapi/fastapi/pull/12483) by [@devfernandoa](https://github.com/devfernandoa).
|
||||
|
||||
### 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).
|
||||
|
||||
## 0.115.3
|
||||
|
||||
### Upgrades
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
||||
|
|
|
|||
|
|
@ -266,7 +266,6 @@ markdown_extensions:
|
|||
|
||||
# Python Markdown Extensions
|
||||
pymdownx.betterem:
|
||||
smart_enable: all
|
||||
pymdownx.caret:
|
||||
pymdownx.highlight:
|
||||
line_spans: __span
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
# Usando Dataclasses
|
||||
|
||||
FastAPI é construído em cima do **Pydantic**, e eu tenho mostrado como usar modelos Pydantic para declarar requisições e respostas.
|
||||
|
||||
Mas o FastAPI também suporta o uso de <a href="https://docs.python.org/3/library/dataclasses.html" class="external-link" target="_blank">`dataclasses`</a> da mesma forma:
|
||||
|
||||
```Python hl_lines="1 7-12 19-20"
|
||||
{!../../docs_src/dataclasses/tutorial001.py!}
|
||||
```
|
||||
|
||||
Isso ainda é suportado graças ao **Pydantic**, pois ele tem <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel" class="external-link" target="_blank">suporte interno para `dataclasses`</a>.
|
||||
|
||||
Então, mesmo com o código acima que não usa Pydantic explicitamente, o FastAPI está usando Pydantic para converter essas dataclasses padrão para a versão do Pydantic.
|
||||
|
||||
E claro, ele suporta o mesmo:
|
||||
|
||||
* validação de dados
|
||||
* serialização de dados
|
||||
* documentação de dados, etc.
|
||||
|
||||
Isso funciona da mesma forma que com os modelos Pydantic. E na verdade é alcançado da mesma maneira por baixo dos panos, usando Pydantic.
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Lembre-se de que dataclasses não podem fazer tudo o que os modelos Pydantic podem fazer.
|
||||
|
||||
Então, você ainda pode precisar usar modelos Pydantic.
|
||||
|
||||
Mas se você tem um monte de dataclasses por aí, este é um truque legal para usá-las para alimentar uma API web usando FastAPI. 🤓
|
||||
|
||||
///
|
||||
|
||||
## Dataclasses em `response_model`
|
||||
|
||||
Você também pode usar `dataclasses` no parâmetro `response_model`:
|
||||
|
||||
```Python hl_lines="1 7-13 19"
|
||||
{!../../docs_src/dataclasses/tutorial002.py!}
|
||||
```
|
||||
|
||||
A dataclass será automaticamente convertida para uma dataclass Pydantic.
|
||||
|
||||
Dessa forma, seu esquema aparecerá na interface de documentação da API:
|
||||
|
||||
<img src="/img/tutorial/dataclasses/image01.png">
|
||||
|
||||
## Dataclasses em Estruturas de Dados Aninhadas
|
||||
|
||||
Você também pode combinar `dataclasses` com outras anotações de tipo para criar estruturas de dados aninhadas.
|
||||
|
||||
Em alguns casos, você ainda pode ter que usar a versão do Pydantic das `dataclasses`. Por exemplo, se você tiver erros com a documentação da API gerada automaticamente.
|
||||
|
||||
Nesse caso, você pode simplesmente trocar as `dataclasses` padrão por `pydantic.dataclasses`, que é um substituto direto:
|
||||
|
||||
```{ .python .annotate hl_lines="1 5 8-11 14-17 23-25 28" }
|
||||
{!../../docs_src/dataclasses/tutorial003.py!}
|
||||
```
|
||||
|
||||
1. Ainda importamos `field` das `dataclasses` padrão.
|
||||
|
||||
2. `pydantic.dataclasses` é um substituto direto para `dataclasses`.
|
||||
|
||||
3. A dataclass `Author` inclui uma lista de dataclasses `Item`.
|
||||
|
||||
4. A dataclass `Author` é usada como o parâmetro `response_model`.
|
||||
|
||||
5. Você pode usar outras anotações de tipo padrão com dataclasses como o corpo da requisição.
|
||||
|
||||
Neste caso, é uma lista de dataclasses `Item`.
|
||||
|
||||
6. Aqui estamos retornando um dicionário que contém `items`, que é uma lista de dataclasses.
|
||||
|
||||
O FastAPI ainda é capaz de <abbr title="converter os dados para um formato que pode ser transmitido">serializar</abbr> os dados para JSON.
|
||||
|
||||
7. Aqui o `response_model` está usando uma anotação de tipo de uma lista de dataclasses `Author`.
|
||||
|
||||
Novamente, você pode combinar `dataclasses` com anotações de tipo padrão.
|
||||
|
||||
8. Note que esta *função de operação de rota* usa `def` regular em vez de `async def`.
|
||||
|
||||
Como sempre, no FastAPI você pode combinar `def` e `async def` conforme necessário.
|
||||
|
||||
Se você precisar de uma atualização sobre quando usar qual, confira a seção _"Com pressa?"_ na documentação sobre [`async` e `await`](../async.md#in-a-hurry){.internal-link target=_blank}.
|
||||
|
||||
9. Esta *função de operação de rota* não está retornando dataclasses (embora pudesse), mas uma lista de dicionários com dados internos.
|
||||
|
||||
O FastAPI usará o parâmetro `response_model` (que inclui dataclasses) para converter a resposta.
|
||||
|
||||
Você pode combinar `dataclasses` com outras anotações de tipo em muitas combinações diferentes para formar estruturas de dados complexas.
|
||||
|
||||
Confira as dicas de anotação no código acima para ver mais detalhes específicos.
|
||||
|
||||
## Saiba Mais
|
||||
|
||||
Você também pode combinar `dataclasses` com outros modelos Pydantic, herdar deles, incluí-los em seus próprios modelos, etc.
|
||||
|
||||
Para saber mais, confira a <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/" class="external-link" target="_blank">documentação do Pydantic sobre dataclasses</a>.
|
||||
|
||||
## Versão
|
||||
|
||||
Isso está disponível desde a versão `0.67.0` do FastAPI. 🔖
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
# Requisições Personalizadas e Classes da APIRoute
|
||||
|
||||
Em algum casos, você pode querer sobreescrever a lógica usada pelas classes `Request`e `APIRoute`.
|
||||
|
||||
Em particular, isso pode ser uma boa alternativa para uma lógica em um middleware
|
||||
|
||||
Por exemplo, se você quiser ler ou manipular o corpo da requisição antes que ele seja processado pela sua aplicação.
|
||||
|
||||
/// danger | Perigo
|
||||
|
||||
Isso é um recurso "avançado".
|
||||
|
||||
Se você for um iniciante em **FastAPI** você deve considerar pular essa seção.
|
||||
|
||||
///
|
||||
|
||||
## Casos de Uso
|
||||
|
||||
Alguns casos de uso incluem:
|
||||
|
||||
* Converter requisições não-JSON para JSON (por exemplo, <a href="https://msgpack.org/index.html" class="external-link" target="_blank">`msgpack`</a>).
|
||||
* Descomprimir corpos de requisição comprimidos com gzip.
|
||||
* Registrar automaticamente todos os corpos de requisição.
|
||||
|
||||
## Manipulando codificações de corpo de requisição personalizadas
|
||||
|
||||
Vamos ver como usar uma subclasse personalizada de `Request` para descomprimir requisições gzip.
|
||||
|
||||
E uma subclasse de `APIRoute` para usar essa classe de requisição personalizada.
|
||||
|
||||
### Criar uma classe `GzipRequest` personalizada
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Isso é um exemplo de brincadeira para demonstrar como funciona, se você precisar de suporte para Gzip, você pode usar o [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware){.internal-link target=_blank} fornecido.
|
||||
|
||||
///
|
||||
|
||||
Primeiro, criamos uma classe `GzipRequest`, que irá sobrescrever o método `Request.body()` para descomprimir o corpo na presença de um cabeçalho apropriado.
|
||||
|
||||
Se não houver `gzip` no cabeçalho, ele não tentará descomprimir o corpo.
|
||||
|
||||
Dessa forma, a mesma classe de rota pode lidar com requisições comprimidas ou não comprimidas.
|
||||
|
||||
```Python hl_lines="8-15"
|
||||
{!../../docs_src/custom_request_and_route/tutorial001.py!}
|
||||
```
|
||||
|
||||
### Criar uma classe `GzipRoute` personalizada
|
||||
|
||||
Em seguida, criamos uma subclasse personalizada de `fastapi.routing.APIRoute` que fará uso do `GzipRequest`.
|
||||
|
||||
Dessa vez, ele irá sobrescrever o método `APIRoute.get_route_handler()`.
|
||||
|
||||
Esse método retorna uma função. E essa função é o que irá receber uma requisição e retornar uma resposta.
|
||||
|
||||
Aqui nós usamos para criar um `GzipRequest` a partir da requisição original.
|
||||
|
||||
```Python hl_lines="18-26"
|
||||
{!../../docs_src/custom_request_and_route/tutorial001.py!}
|
||||
```
|
||||
|
||||
/// note | Detalhes Técnicos
|
||||
|
||||
Um `Request` também tem um `request.receive`, que é uma função para "receber" o corpo da requisição.
|
||||
|
||||
Um `Request` também tem um `request.receive`, que é uma função para "receber" o corpo da requisição.
|
||||
|
||||
O dicionário `scope` e a função `receive` são ambos parte da especificação ASGI.
|
||||
|
||||
E essas duas coisas, `scope` e `receive`, são o que é necessário para criar uma nova instância de `Request`.
|
||||
|
||||
Para aprender mais sobre o `Request` confira a <a href="https://www.starlette.io/requests/" class="external-link" target="_blank">documentação do Starlette sobre Requests</a>.
|
||||
|
||||
///
|
||||
|
||||
A única coisa que a função retornada por `GzipRequest.get_route_handler` faz de diferente é converter o `Request` para um `GzipRequest`.
|
||||
|
||||
Fazendo isso, nosso `GzipRequest` irá cuidar de descomprimir os dados (se necessário) antes de passá-los para nossas *operações de rota*.
|
||||
|
||||
Depois disso, toda a lógica de processamento é a mesma.
|
||||
|
||||
Mas por causa das nossas mudanças em `GzipRequest.body`, o corpo da requisição será automaticamente descomprimido quando for carregado pelo **FastAPI** quando necessário.
|
||||
|
||||
## Acessando o corpo da requisição em um manipulador de exceção
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Para resolver esse mesmo problema, é provavelmente muito mais fácil usar o `body` em um manipulador personalizado para `RequestValidationError` ([Tratando Erros](../tutorial/handling-errors.md#use-the-requestvalidationerror-body){.internal-link target=_blank}).
|
||||
|
||||
Mas esse exemplo ainda é valido e mostra como interagir com os componentes internos.
|
||||
|
||||
///
|
||||
|
||||
Também podemos usar essa mesma abordagem para acessar o corpo da requisição em um manipulador de exceção.
|
||||
|
||||
Tudo que precisamos fazer é manipular a requisição dentro de um bloco `try`/`except`:
|
||||
|
||||
```Python hl_lines="13 15"
|
||||
{!../../docs_src/custom_request_and_route/tutorial002.py!}
|
||||
```
|
||||
|
||||
Se uma exceção ocorrer, a instância `Request` ainda estará em escopo, então podemos ler e fazer uso do corpo da requisição ao lidar com o erro:
|
||||
|
||||
```Python hl_lines="16-18"
|
||||
{!../../docs_src/custom_request_and_route/tutorial002.py!}
|
||||
```
|
||||
|
||||
## Classe `APIRoute` personalizada em um router
|
||||
|
||||
você também pode definir o parametro `route_class` de uma `APIRouter`;
|
||||
|
||||
```Python hl_lines="26"
|
||||
{!../../docs_src/custom_request_and_route/tutorial003.py!}
|
||||
```
|
||||
|
||||
Nesse exemplo, as *operações de rota* sob o `router` irão usar a classe `TimedRoute` personalizada, e terão um cabeçalho extra `X-Response-Time` na resposta com o tempo que levou para gerar a resposta:
|
||||
|
||||
```Python hl_lines="13-20"
|
||||
{!../../docs_src/custom_request_and_route/tutorial003.py!}
|
||||
```
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
|
||||
# Extendendo o OpenAPI
|
||||
|
||||
Existem alguns casos em que pode ser necessário modificar o esquema OpenAPI gerado.
|
||||
|
||||
Nesta seção, você verá como fazer isso.
|
||||
|
||||
## O processo normal
|
||||
|
||||
O processo normal (padrão) é o seguinte:
|
||||
|
||||
Uma aplicação (instância) do `FastAPI` possui um método `.openapi()` que deve retornar o esquema OpenAPI.
|
||||
|
||||
Como parte da criação do objeto de aplicação, uma *operação de rota* para `/openapi.json` (ou para o que você definir como `openapi_url`) é registrada.
|
||||
|
||||
Ela apenas retorna uma resposta JSON com o resultado do método `.openapi()` da aplicação.
|
||||
|
||||
Por padrão, o que o método `.openapi()` faz é verificar se a propriedade `.openapi_schema` tem conteúdo e retorná-lo.
|
||||
|
||||
Se não tiver, ele gera o conteúdo usando a função utilitária em `fastapi.openapi.utils.get_openapi`.
|
||||
|
||||
E essa função `get_openapi()` recebe como parâmetros:
|
||||
|
||||
* `title`: O título do OpenAPI, exibido na documentação.
|
||||
* `version`: A versão da sua API, por exemplo, `2.5.0`.
|
||||
* `openapi_version`: A versão da especificação OpenAPI utilizada. Por padrão, a mais recente: `3.1.0`.
|
||||
* `summary`: Um resumo curto da API.
|
||||
* `description`: A descrição da sua API, que pode incluir markdown e será exibida na documentação.
|
||||
* `routes`: Uma lista de rotas, que são cada uma das *operações de rota* registradas. Elas são obtidas de `app.routes`.
|
||||
|
||||
/// info | Informação
|
||||
|
||||
O parâmetro `summary` está disponível no OpenAPI 3.1.0 e superior, suportado pelo FastAPI 0.99.0 e superior.
|
||||
|
||||
///
|
||||
|
||||
## Sobrescrevendo os padrões
|
||||
|
||||
Com as informações acima, você pode usar a mesma função utilitária para gerar o esquema OpenAPI e sobrescrever cada parte que precisar.
|
||||
|
||||
Por exemplo, vamos adicionar <a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" class="external-link" target="_blank">Extensão OpenAPI do ReDoc para incluir um logo personalizado</a>.
|
||||
|
||||
### **FastAPI** Normal
|
||||
|
||||
Primeiro, escreva toda a sua aplicação **FastAPI** normalmente:
|
||||
|
||||
```Python hl_lines="1 4 7-9"
|
||||
{!../../docs_src/extending_openapi/tutorial001.py!}
|
||||
```
|
||||
|
||||
### Gerar o esquema OpenAPI
|
||||
|
||||
Em seguida, use a mesma função utilitária para gerar o esquema OpenAPI, dentro de uma função `custom_openapi()`:
|
||||
|
||||
```Python hl_lines="2 15-21"
|
||||
{!../../docs_src/extending_openapi/tutorial001.py!}
|
||||
```
|
||||
|
||||
### Modificar o esquema OpenAPI
|
||||
|
||||
Agora, você pode adicionar a extensão do ReDoc, incluindo um `x-logo` personalizado ao "objeto" `info` no esquema OpenAPI:
|
||||
|
||||
```Python hl_lines="22-24"
|
||||
{!../../docs_src/extending_openapi/tutorial001.py!}
|
||||
```
|
||||
|
||||
### Armazenar em cache o esquema OpenAPI
|
||||
|
||||
Você pode usar a propriedade `.openapi_schema` como um "cache" para armazenar o esquema gerado.
|
||||
|
||||
Dessa forma, sua aplicação não precisará gerar o esquema toda vez que um usuário abrir a documentação da sua API.
|
||||
|
||||
Ele será gerado apenas uma vez, e o mesmo esquema armazenado em cache será utilizado nas próximas requisições.
|
||||
|
||||
```Python hl_lines="13-14 25-26"
|
||||
{!../../docs_src/extending_openapi/tutorial001.py!}
|
||||
```
|
||||
|
||||
### Sobrescrever o método
|
||||
|
||||
Agora, você pode substituir o método `.openapi()` pela sua nova função.
|
||||
|
||||
```Python hl_lines="29"
|
||||
{!../../docs_src/extending_openapi/tutorial001.py!}
|
||||
```
|
||||
|
||||
### Verificar
|
||||
|
||||
Uma vez que você acessar <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>, verá que está usando seu logo personalizado (neste exemplo, o logo do **FastAPI**):
|
||||
|
||||
<img src="/docs/en/docs/img/tutorial/extending-openapi/image01.png">
|
||||
|
|
@ -0,0 +1,258 @@
|
|||
# Esquemas OpenAPI Separados para Entrada e Saída ou Não
|
||||
|
||||
Ao usar **Pydantic v2**, o OpenAPI gerado é um pouco mais exato e **correto** do que antes. 😎
|
||||
|
||||
Inclusive, em alguns casos, ele terá até **dois JSON Schemas** no OpenAPI para o mesmo modelo Pydantic, para entrada e saída, dependendo se eles possuem **valores padrão**.
|
||||
|
||||
Vamos ver como isso funciona e como alterar se for necessário.
|
||||
|
||||
## Modelos Pydantic para Entrada e Saída
|
||||
|
||||
Digamos que você tenha um modelo Pydantic com valores padrão, como este:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py[ln:1-7]!}
|
||||
|
||||
# Code below omitted 👇
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>👀 Visualização completa do arquivo</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>👀 Visualização completa do arquivo</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>👀 Visualização completa do arquivo</summary>
|
||||
|
||||
```Python
|
||||
{!> ../../docs_src/separate_openapi_schemas/tutorial001.py!}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
////
|
||||
|
||||
### Modelo para Entrada
|
||||
|
||||
Se você usar esse modelo como entrada, como aqui:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python hl_lines="14"
|
||||
{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py[ln:1-15]!}
|
||||
|
||||
# Code below omitted 👇
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>👀 Visualização completa do arquivo</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>👀 Visualização completa do arquivo</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>👀 Visualização completa do arquivo</summary>
|
||||
|
||||
```Python
|
||||
{!> ../../docs_src/separate_openapi_schemas/tutorial001.py!}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
////
|
||||
|
||||
... então o campo `description` não será obrigatório. Porque ele tem um valor padrão de `None`.
|
||||
|
||||
### Modelo de Entrada na Documentação
|
||||
|
||||
Você pode confirmar que na documentação, o campo `description` não tem um **asterisco vermelho**, não é marcado como obrigatório:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image01.png">
|
||||
</div>
|
||||
|
||||
### Modelo para Saída
|
||||
|
||||
Mas se você usar o mesmo modelo como saída, como aqui:
|
||||
|
||||
//// 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!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
... então, como `description` tem um valor padrão, se você **não retornar nada** para esse campo, ele ainda terá o **valor padrão**.
|
||||
|
||||
### Modelo para Dados de Resposta de Saída
|
||||
|
||||
Se você interagir com a documentação e verificar a resposta, mesmo que o código não tenha adicionado nada em um dos campos `description`, a resposta JSON contém o valor padrão (`null`):
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image02.png">
|
||||
</div>
|
||||
|
||||
Isso significa que ele **sempre terá um valor**, só que às vezes o valor pode ser `None` (ou `null` em termos de JSON).
|
||||
|
||||
Isso quer dizer que, os clientes que usam sua API não precisam verificar se o valor existe ou não, eles podem **assumir que o campo sempre estará lá**, mas que em alguns casos terá o valor padrão de `None`.
|
||||
|
||||
A maneira de descrever isso no OpenAPI é marcar esse campo como **obrigatório**, porque ele sempre estará lá.
|
||||
|
||||
Por causa disso, o JSON Schema para um modelo pode ser diferente dependendo se ele é usado para **entrada ou saída**:
|
||||
|
||||
* para **entrada**, o `description` **não será obrigatório**
|
||||
* para **saída**, ele será **obrigatório** (e possivelmente `None`, ou em termos de JSON, `null`)
|
||||
|
||||
### Modelo para Saída na Documentação
|
||||
|
||||
Você pode verificar o modelo de saída na documentação também, ambos `name` e `description` são marcados como **obrigatórios** com um **asterisco vermelho**:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image03.png">
|
||||
</div>
|
||||
|
||||
### Modelo para Entrada e Saída na Documentação
|
||||
|
||||
E se você verificar todos os Schemas disponíveis (JSON Schemas) no OpenAPI, verá que há dois, um `Item-Input` e um `Item-Output`.
|
||||
|
||||
Para `Item-Input`, `description` **não é obrigatório**, não tem um asterisco vermelho.
|
||||
|
||||
Mas para `Item-Output`, `description` **é obrigatório**, tem um asterisco vermelho.
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image04.png">
|
||||
</div>
|
||||
|
||||
Com esse recurso do **Pydantic v2**, sua documentação da API fica mais **precisa**, e se você tiver clientes e SDKs gerados automaticamente, eles serão mais precisos também, proporcionando uma melhor **experiência para desenvolvedores** e consistência. 🎉
|
||||
|
||||
## Não Separe Schemas
|
||||
|
||||
Agora, há alguns casos em que você pode querer ter o **mesmo esquema para entrada e saída**.
|
||||
|
||||
Provavelmente, o principal caso de uso para isso é se você já tem algum código de cliente/SDK gerado automaticamente e não quer atualizar todo o código de cliente/SDK gerado ainda, você provavelmente vai querer fazer isso em algum momento, mas talvez não agora.
|
||||
|
||||
Nesse caso, você pode desativar esse recurso no **FastAPI**, com o parâmetro `separate_input_output_schemas=False`.
|
||||
|
||||
/// info | Informação
|
||||
|
||||
O suporte para `separate_input_output_schemas` foi adicionado no 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!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
### Mesmo Esquema para Modelos de Entrada e Saída na Documentação
|
||||
|
||||
E agora haverá um único esquema para entrada e saída para o modelo, apenas `Item`, e `description` **não será obrigatório**:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image05.png">
|
||||
</div>
|
||||
|
||||
Esse é o mesmo comportamento do Pydantic v1. 🤓
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
# Modelos de Parâmetros do Cabeçalho
|
||||
|
||||
Se você possui um grupo de **parâmetros de cabeçalho** relacionados, você pode criar um **modelo do Pydantic** para declará-los.
|
||||
|
||||
Isso vai lhe permitir **reusar o modelo** em **múltiplos lugares** e também declarar validações e metadadados para todos os parâmetros de uma vez. 😎
|
||||
|
||||
/// note | Nota
|
||||
|
||||
Isso é possível desde a versão `0.115.0` do FastAPI. 🤓
|
||||
|
||||
///
|
||||
|
||||
## Parâmetros do Cabeçalho com um Modelo Pydantic
|
||||
|
||||
Declare os **parâmetros de cabeçalho** que você precisa em um **modelo do Pydantic**, e então declare o parâmetro como `Header`:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python hl_lines="9-14 18"
|
||||
{!> ../../docs_src/header_param_models/tutorial001_an_py310.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
```Python hl_lines="9-14 18"
|
||||
{!> ../../docs_src/header_param_models/tutorial001_an_py39.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.8+
|
||||
|
||||
```Python hl_lines="10-15 19"
|
||||
{!> ../../docs_src/header_param_models/tutorial001_an.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.10+ non-Annotated
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Utilize a versão com `Annotated` se possível.
|
||||
|
||||
///
|
||||
|
||||
```Python hl_lines="7-12 16"
|
||||
{!> ../../docs_src/header_param_models/tutorial001_py310.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ non-Annotated
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Utilize a versão com `Annotated` se possível.
|
||||
|
||||
///
|
||||
|
||||
```Python hl_lines="9-14 18"
|
||||
{!> ../../docs_src/header_param_models/tutorial001_py39.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.8+ non-Annotated
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Utilize a versão com `Annotated` se possível.
|
||||
|
||||
///
|
||||
|
||||
```Python hl_lines="7-12 16"
|
||||
{!> ../../docs_src/header_param_models/tutorial001_py310.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
O **FastAPI** irá **extrair** os dados de **cada campo** a partir dos **cabeçalhos** da requisição e te retornará o modelo do Pydantic que você definiu.
|
||||
|
||||
### Checando a documentação
|
||||
|
||||
Você pode ver os headers necessários na interface gráfica da documentação em `/docs`:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/header-param-models/image01.png">
|
||||
</div>
|
||||
|
||||
### Proibindo Cabeçalhos adicionais
|
||||
|
||||
Em alguns casos de uso especiais (provavelmente não muito comuns), você pode querer **restringir** os cabeçalhos que você quer receber.
|
||||
|
||||
Você pode usar a configuração dos modelos do Pydantic para proibir (`forbid`) quaisquer campos `extra`:
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
```Python hl_lines="10"
|
||||
{!> ../../docs_src/header_param_models/tutorial002_an_py310.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+
|
||||
|
||||
```Python hl_lines="10"
|
||||
{!> ../../docs_src/header_param_models/tutorial002_an_py39.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.8+
|
||||
|
||||
```Python hl_lines="11"
|
||||
{!> ../../docs_src/header_param_models/tutorial002_an.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.10+ non-Annotated
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Utilize a versão com `Annotated` se possível.
|
||||
|
||||
///
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!> ../../docs_src/header_param_models/tutorial002_py310.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+ non-Annotated
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Utilize a versão com `Annotated` se possível.
|
||||
|
||||
///
|
||||
|
||||
```Python hl_lines="10"
|
||||
{!> ../../docs_src/header_param_models/tutorial002_py39.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.8+ non-Annotated
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Utilize a versão com `Annotated` se possível.
|
||||
|
||||
///
|
||||
|
||||
```Python hl_lines="10"
|
||||
{!> ../../docs_src/header_param_models/tutorial002.py!}
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
Se um cliente tentar enviar alguns **cabeçalhos extra**, eles irão receber uma resposta de **erro**.
|
||||
|
||||
Por exemplo, se o cliente tentar enviar um cabeçalho `tool` com o valor `plumbus`, ele irá receber uma resposta de **erro** informando que o parâmetro do cabeçalho `tool` não é permitido:
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"type": "extra_forbidden",
|
||||
"loc": ["header", "tool"],
|
||||
"msg": "Extra inputs are not permitted",
|
||||
"input": "plumbus",
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Resumo
|
||||
|
||||
Você pode utilizar **modelos do Pydantic** para declarar **cabeçalhos** no **FastAPI**. 😎
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
# 在雲端部署 FastAPI
|
||||
|
||||
你幾乎可以使用 **任何雲端供應商** 來部署你的 FastAPI 應用程式。
|
||||
你幾乎可以使用**任何雲端供應商**來部署你的 FastAPI 應用程式。
|
||||
|
||||
在大多數情況下,主要的雲端供應商都有部署 FastAPI 的指南。
|
||||
|
||||
## 雲端供應商 - 贊助商
|
||||
|
||||
一些雲端供應商 ✨ [**贊助 FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨,這確保了 FastAPI 及其 **生態系統** 持續健康地 **發展**。
|
||||
一些雲端供應商 ✨ [**贊助 FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨,這確保了 FastAPI 及其**生態系統**持續健康地**發展**。
|
||||
|
||||
這也展現了他們對 FastAPI 和其 **社群**(包括你)的真正承諾,他們不僅希望為你提供 **優質的服務**,還希望確保你擁有一個 **良好且健康的框架**:FastAPI。🙇
|
||||
這也展現了他們對 FastAPI 和其**社群**(包括你)的真正承諾,他們不僅希望為你提供**優質的服務**,還希望確保你擁有一個**良好且健康的框架**:FastAPI。🙇
|
||||
|
||||
你可能會想嘗試他們的服務,以下有他們的指南:
|
||||
|
||||
|
|
|
|||
|
|
@ -4,17 +4,17 @@
|
|||
|
||||
## 部署是什麼意思
|
||||
|
||||
**部署** 應用程式指的是執行一系列必要的步驟,使其能夠 **讓使用者存取和使用**。
|
||||
**部署**應用程式指的是執行一系列必要的步驟,使其能夠**讓使用者存取和使用**。
|
||||
|
||||
對於一個 **Web API**,部署通常涉及將其放置在 **遠端伺服器** 上,並使用性能優良且穩定的 **伺服器程式**,確保使用者能夠高效、無中斷地存取應用程式,且不會遇到問題。
|
||||
對於一個 **Web API**,部署通常涉及將其放置在**遠端伺服器**上,並使用性能優良且穩定的**伺服器程式**,確保使用者能夠高效、無中斷地存取應用程式,且不會遇到問題。
|
||||
|
||||
這與 **開發** 階段形成鮮明對比,在 **開發** 階段,你會不斷更改程式碼、破壞程式碼、修復程式碼,然後停止和重新啟動伺服器等。
|
||||
這與**開發**階段形成鮮明對比,在**開發**階段,你會不斷更改程式碼、破壞程式碼、修復程式碼,然後停止和重新啟動伺服器等。
|
||||
|
||||
## 部署策略
|
||||
|
||||
根據你的使用場景和使用工具,有多種方法可以實現此目的。
|
||||
|
||||
你可以使用一些工具自行 **部署伺服器**,你也可以使用能為你完成部分工作的 **雲端服務**,或其他可能的選項。
|
||||
你可以使用一些工具自行**部署伺服器**,你也可以使用能為你完成部分工作的**雲端服務**,或其他可能的選項。
|
||||
|
||||
我將向你展示在部署 **FastAPI** 應用程式時你可能應該記住的一些主要概念(儘管其中大部分適用於任何其他類型的 Web 應用程式)。
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
# 使用指南 - 範例集
|
||||
|
||||
在這裡,你將會看到**不同主題**的範例或「如何使用」的指南。
|
||||
|
||||
大多數這些想法都是**獨立**的,在大多數情況下,你只需要研究那些直接適用於**你的專案**的東西。
|
||||
|
||||
如果有些東西看起來很有趣且對你的專案很有用的話再去讀它,否則你可能可以跳過它們。
|
||||
|
||||
/// tip
|
||||
|
||||
如果你想要以結構化的方式**學習 FastAPI**(推薦),請前往[教學 - 使用者指南](../tutorial/index.md){.internal-link target=_blank}逐章閱讀。
|
||||
|
||||
///
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
# 教學 - 使用者指南
|
||||
|
||||
本教學將一步一步展示如何使用 **FastAPI** 及其大多數功能。
|
||||
|
||||
每個部分都是在前一部分的基礎上逐步建置的,但內容結構是按主題分開的,因此你可以直接跳到任何特定的部分,解決你具體的 API 需求。
|
||||
|
||||
它也被設計成可作為未來的參考,讓你隨時回來查看所需的內容。
|
||||
|
||||
## 運行程式碼
|
||||
|
||||
所有程式碼區塊都可以直接複製和使用(它們實際上是經過測試的 Python 檔案)。
|
||||
|
||||
要運行任何範例,請將程式碼複製到 `main.py` 檔案,並使用以下命令啟動 `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: ['/home/user/code/awesomeapp']
|
||||
<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.
|
||||
</pre>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
**強烈建議**你編寫或複製程式碼、進行修改並在本地端運行。
|
||||
|
||||
在編輯器中使用它,才能真正體會到 FastAPI 的好處,可以看到你只需編寫少量程式碼,以及所有的型別檢查、自動補齊等功能。
|
||||
|
||||
---
|
||||
|
||||
## 安裝 FastAPI
|
||||
|
||||
第一步是安裝 FastAPI。
|
||||
|
||||
確保你建立一個[虛擬環境](../virtual-environments.md){.internal-link target=_blank},啟用它,然後**安裝 FastAPI**:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install "fastapi[standard]"
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// note
|
||||
|
||||
當你使用 `pip install "fastapi[standard]"` 安裝時,會包含一些預設的可選標準相依項。
|
||||
|
||||
如果你不想包含那些可選的相依項,你可以使用 `pip install fastapi` 來安裝。
|
||||
|
||||
///
|
||||
|
||||
## 進階使用者指南
|
||||
|
||||
還有一個**進階使用者指南**你可以稍後閱讀。
|
||||
|
||||
**進階使用者指南**建立在這個教學之上,使用相同的概念,並教你一些額外的功能。
|
||||
|
||||
但首先你應該閱讀**教學 - 使用者指南**(你正在閱讀的內容)。
|
||||
|
||||
它被設計成你可以使用**教學 - 使用者指南**來建立一個完整的應用程式,然後根據你的需求,使用一些額外的想法來擴展它。
|
||||
|
|
@ -2298,7 +2298,7 @@ def Security( # noqa: N802
|
|||
dependency.
|
||||
|
||||
The term "scope" comes from the OAuth2 specification, it seems to be
|
||||
intentionaly vague and interpretable. It normally refers to permissions,
|
||||
intentionally vague and interpretable. It normally refers to permissions,
|
||||
in cases to roles.
|
||||
|
||||
These scopes are integrated with OpenAPI (and the API docs at `/docs`).
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ class OAuth2PasswordRequestForm:
|
|||
```
|
||||
|
||||
Note that for OAuth2 the scope `items:read` is a single scope in an opaque string.
|
||||
You could have custom internal logic to separate it by colon caracters (`:`) or
|
||||
You could have custom internal logic to separate it by colon characters (`:`) or
|
||||
similar, and get the two parts `items` and `read`. Many applications do that to
|
||||
group and organize permissions, you could do it as well in your application, just
|
||||
know that that it is application specific, it's not part of the specification.
|
||||
|
|
@ -194,7 +194,7 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):
|
|||
```
|
||||
|
||||
Note that for OAuth2 the scope `items:read` is a single scope in an opaque string.
|
||||
You could have custom internal logic to separate it by colon caracters (`:`) or
|
||||
You could have custom internal logic to separate it by colon characters (`:`) or
|
||||
similar, and get the two parts `items` and `read`. Many applications do that to
|
||||
group and organize permissions, you could do it as well in your application, just
|
||||
know that that it is application specific, it's not part of the specification.
|
||||
|
|
|
|||
Loading…
Reference in New Issue