../../../docs_src/encoder/tutorial001.py!}
+ ```Python hl_lines="4 21"
+ {!> ../../../docs_src/encoder/tutorial001_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="4 21"
- {!> ../../../docs_src/encoder/tutorial001_py310.py!}
+ ```Python hl_lines="5 22"
+ {!> ../../../docs_src/encoder/tutorial001.py!}
```
In this example, it would convert the Pydantic model to a `dict`, and the `datetime` to a `str`.
diff --git a/docs/en/docs/tutorial/extra-data-types.md b/docs/en/docs/tutorial/extra-data-types.md
index fb3efd318..7d6ffbc78 100644
--- a/docs/en/docs/tutorial/extra-data-types.md
+++ b/docs/en/docs/tutorial/extra-data-types.md
@@ -55,28 +55,76 @@ Here are some of the additional data types you can use:
Here's an example *path operation* with parameters using some of the above types.
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="1 3 12-16"
- {!> ../../../docs_src/extra_data_types/tutorial001.py!}
+ {!> ../../../docs_src/extra_data_types/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="1 3 12-16"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="1 3 13-17"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="1 2 11-15"
{!> ../../../docs_src/extra_data_types/tutorial001_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="1 2 12-16"
+ {!> ../../../docs_src/extra_data_types/tutorial001.py!}
+ ```
+
Note that the parameters inside the function have their natural data type, and you can, for example, perform normal date manipulations, like:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="18-19"
- {!> ../../../docs_src/extra_data_types/tutorial001.py!}
+ {!> ../../../docs_src/extra_data_types/tutorial001_an_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.9+"
+
+ ```Python hl_lines="18-19"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="19-20"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="17-18"
{!> ../../../docs_src/extra_data_types/tutorial001_py310.py!}
```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="18-19"
+ {!> ../../../docs_src/extra_data_types/tutorial001.py!}
+ ```
diff --git a/docs/en/docs/tutorial/extra-models.md b/docs/en/docs/tutorial/extra-models.md
index 72fc74894..e91e879e4 100644
--- a/docs/en/docs/tutorial/extra-models.md
+++ b/docs/en/docs/tutorial/extra-models.md
@@ -17,16 +17,16 @@ This is especially the case for user models, because:
Here's a general idea of how the models could look like with their password fields and the places where they are used:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41"
- {!> ../../../docs_src/extra_models/tutorial001.py!}
+ ```Python hl_lines="7 9 14 20 22 27-28 31-33 38-39"
+ {!> ../../../docs_src/extra_models/tutorial001_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="7 9 14 20 22 27-28 31-33 38-39"
- {!> ../../../docs_src/extra_models/tutorial001_py310.py!}
+ ```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41"
+ {!> ../../../docs_src/extra_models/tutorial001.py!}
```
### About `**user_in.dict()`
@@ -158,16 +158,16 @@ All the data conversion, validation, documentation, etc. will still work as norm
That way, we can declare just the differences between the models (with plaintext `password`, with `hashed_password` and without password):
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="9 15-16 19-20 23-24"
- {!> ../../../docs_src/extra_models/tutorial002.py!}
+ ```Python hl_lines="7 13-14 17-18 21-22"
+ {!> ../../../docs_src/extra_models/tutorial002_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="7 13-14 17-18 21-22"
- {!> ../../../docs_src/extra_models/tutorial002_py310.py!}
+ ```Python hl_lines="9 15-16 19-20 23-24"
+ {!> ../../../docs_src/extra_models/tutorial002.py!}
```
## `Union` or `anyOf`
@@ -181,16 +181,16 @@ To do that, use the standard Python type hint `Union`, include the most specific type first, followed by the less specific type. In the example below, the more specific `PlaneItem` comes before `CarItem` in `Union[PlaneItem, CarItem]`.
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="1 14-15 18-20 33"
- {!> ../../../docs_src/extra_models/tutorial003.py!}
+ {!> ../../../docs_src/extra_models/tutorial003_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
```Python hl_lines="1 14-15 18-20 33"
- {!> ../../../docs_src/extra_models/tutorial003_py310.py!}
+ {!> ../../../docs_src/extra_models/tutorial003.py!}
```
### `Union` in Python 3.10
@@ -213,16 +213,16 @@ The same way, you can declare responses of lists of objects.
For that, use the standard Python `typing.List` (or just `list` in Python 3.9 and above):
-=== "Python 3.6 and above"
+=== "Python 3.9+"
- ```Python hl_lines="1 20"
- {!> ../../../docs_src/extra_models/tutorial004.py!}
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/extra_models/tutorial004_py39.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.6+"
- ```Python hl_lines="18"
- {!> ../../../docs_src/extra_models/tutorial004_py39.py!}
+ ```Python hl_lines="1 20"
+ {!> ../../../docs_src/extra_models/tutorial004.py!}
```
## Response with arbitrary `dict`
@@ -233,16 +233,16 @@ This is useful if you don't know the valid field/attribute names (that would be
In this case, you can use `typing.Dict` (or just `dict` in Python 3.9 and above):
-=== "Python 3.6 and above"
+=== "Python 3.9+"
- ```Python hl_lines="1 8"
- {!> ../../../docs_src/extra_models/tutorial005.py!}
+ ```Python hl_lines="6"
+ {!> ../../../docs_src/extra_models/tutorial005_py39.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.6+"
- ```Python hl_lines="6"
- {!> ../../../docs_src/extra_models/tutorial005_py39.py!}
+ ```Python hl_lines="1 8"
+ {!> ../../../docs_src/extra_models/tutorial005.py!}
```
## Recap
diff --git a/docs/en/docs/tutorial/header-params.md b/docs/en/docs/tutorial/header-params.md
index 8e294416c..9e928cdc6 100644
--- a/docs/en/docs/tutorial/header-params.md
+++ b/docs/en/docs/tutorial/header-params.md
@@ -6,36 +6,84 @@ You can define Header parameters the same way you define `Query`, `Path` and `Co
First import `Header`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="3"
- {!> ../../../docs_src/header_params/tutorial001.py!}
+ {!> ../../../docs_src/header_params/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/header_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/header_params/tutorial001_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="1"
{!> ../../../docs_src/header_params/tutorial001_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/header_params/tutorial001.py!}
+ ```
+
## Declare `Header` parameters
Then declare the header parameters using the same structure as with `Path`, `Query` and `Cookie`.
The first value is the default value, you can pass all the extra validation or annotation parameters:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="9"
- {!> ../../../docs_src/header_params/tutorial001.py!}
+ {!> ../../../docs_src/header_params/tutorial001_an_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/header_params/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/header_params/tutorial001_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial001.py!}
+ ```
+
!!! note "Technical Details"
`Header` is a "sister" class of `Path`, `Query` and `Cookie`. It also inherits from the same common `Param` class.
@@ -60,18 +108,42 @@ So, you can use `user_agent` as you normally would in Python code, instead of ne
If for some reason you need to disable automatic conversion of underscores to hyphens, set the parameter `convert_underscores` of `Header` to `False`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="10"
- {!> ../../../docs_src/header_params/tutorial002.py!}
+ {!> ../../../docs_src/header_params/tutorial002_an_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.9+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/header_params/tutorial002_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/header_params/tutorial002_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="8"
{!> ../../../docs_src/header_params/tutorial002_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/header_params/tutorial002.py!}
+ ```
+
!!! warning
Before setting `convert_underscores` to `False`, bear in mind that some HTTP proxies and servers disallow the usage of headers with underscores.
@@ -85,24 +157,51 @@ You will receive all the values from the duplicate header as a Python `list`.
For example, to declare a header of `X-Token` that can appear more than once, you can write:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="9"
- {!> ../../../docs_src/header_params/tutorial003.py!}
+ {!> ../../../docs_src/header_params/tutorial003_an_py310.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.9+"
```Python hl_lines="9"
- {!> ../../../docs_src/header_params/tutorial003_py39.py!}
+ {!> ../../../docs_src/header_params/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/header_params/tutorial003_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/header_params/tutorial003_py310.py!}
```
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial003_py39.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial003.py!}
+ ```
+
If you communicate with that *path operation* sending two HTTP headers like:
```
diff --git a/docs/en/docs/tutorial/metadata.md b/docs/en/docs/tutorial/metadata.md
index 78f17031a..cf13e7470 100644
--- a/docs/en/docs/tutorial/metadata.md
+++ b/docs/en/docs/tutorial/metadata.md
@@ -101,7 +101,7 @@ You can configure the two documentation user interfaces included:
* **Swagger UI**: served at `/docs`.
* You can set its URL with the parameter `docs_url`.
* You can disable it by setting `docs_url=None`.
-* ReDoc: served at `/redoc`.
+* **ReDoc**: served at `/redoc`.
* You can set its URL with the parameter `redoc_url`.
* You can disable it by setting `redoc_url=None`.
diff --git a/docs/en/docs/tutorial/path-operation-configuration.md b/docs/en/docs/tutorial/path-operation-configuration.md
index 884a762e2..7d4d4bcca 100644
--- a/docs/en/docs/tutorial/path-operation-configuration.md
+++ b/docs/en/docs/tutorial/path-operation-configuration.md
@@ -13,22 +13,22 @@ You can pass directly the `int` code, like `404`.
But if you don't remember what each number code is for, you can use the shortcut constants in `status`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="3 17"
- {!> ../../../docs_src/path_operation_configuration/tutorial001.py!}
+ ```Python hl_lines="1 15"
+ {!> ../../../docs_src/path_operation_configuration/tutorial001_py310.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.9+"
```Python hl_lines="3 17"
{!> ../../../docs_src/path_operation_configuration/tutorial001_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="1 15"
- {!> ../../../docs_src/path_operation_configuration/tutorial001_py310.py!}
+ ```Python hl_lines="3 17"
+ {!> ../../../docs_src/path_operation_configuration/tutorial001.py!}
```
That status code will be used in the response and will be added to the OpenAPI schema.
@@ -42,22 +42,22 @@ That status code will be used in the response and will be added to the OpenAPI s
You can add tags to your *path operation*, pass the parameter `tags` with a `list` of `str` (commonly just one `str`):
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="17 22 27"
- {!> ../../../docs_src/path_operation_configuration/tutorial002.py!}
+ ```Python hl_lines="15 20 25"
+ {!> ../../../docs_src/path_operation_configuration/tutorial002_py310.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.9+"
```Python hl_lines="17 22 27"
{!> ../../../docs_src/path_operation_configuration/tutorial002_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="15 20 25"
- {!> ../../../docs_src/path_operation_configuration/tutorial002_py310.py!}
+ ```Python hl_lines="17 22 27"
+ {!> ../../../docs_src/path_operation_configuration/tutorial002.py!}
```
They will be added to the OpenAPI schema and used by the automatic documentation interfaces:
@@ -80,22 +80,22 @@ In these cases, it could make sense to store the tags in an `Enum`.
You can add a `summary` and `description`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="20-21"
- {!> ../../../docs_src/path_operation_configuration/tutorial003.py!}
+ ```Python hl_lines="18-19"
+ {!> ../../../docs_src/path_operation_configuration/tutorial003_py310.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.9+"
```Python hl_lines="20-21"
{!> ../../../docs_src/path_operation_configuration/tutorial003_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="18-19"
- {!> ../../../docs_src/path_operation_configuration/tutorial003_py310.py!}
+ ```Python hl_lines="20-21"
+ {!> ../../../docs_src/path_operation_configuration/tutorial003.py!}
```
## Description from docstring
@@ -104,22 +104,22 @@ As descriptions tend to be long and cover multiple lines, you can declare the *p
You can write Markdown in the docstring, it will be interpreted and displayed correctly (taking into account docstring indentation).
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="19-27"
- {!> ../../../docs_src/path_operation_configuration/tutorial004.py!}
+ ```Python hl_lines="17-25"
+ {!> ../../../docs_src/path_operation_configuration/tutorial004_py310.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.9+"
```Python hl_lines="19-27"
{!> ../../../docs_src/path_operation_configuration/tutorial004_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="17-25"
- {!> ../../../docs_src/path_operation_configuration/tutorial004_py310.py!}
+ ```Python hl_lines="19-27"
+ {!> ../../../docs_src/path_operation_configuration/tutorial004.py!}
```
It will be used in the interactive docs:
@@ -130,22 +130,22 @@ It will be used in the interactive docs:
You can specify the response description with the parameter `response_description`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="21"
- {!> ../../../docs_src/path_operation_configuration/tutorial005.py!}
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/path_operation_configuration/tutorial005_py310.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.9+"
```Python hl_lines="21"
{!> ../../../docs_src/path_operation_configuration/tutorial005_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="19"
- {!> ../../../docs_src/path_operation_configuration/tutorial005_py310.py!}
+ ```Python hl_lines="21"
+ {!> ../../../docs_src/path_operation_configuration/tutorial005.py!}
```
!!! info
diff --git a/docs/en/docs/tutorial/path-params-numeric-validations.md b/docs/en/docs/tutorial/path-params-numeric-validations.md
index cec54b0fb..9255875d6 100644
--- a/docs/en/docs/tutorial/path-params-numeric-validations.md
+++ b/docs/en/docs/tutorial/path-params-numeric-validations.md
@@ -4,38 +4,93 @@ In the same way that you can declare more validations and metadata for query par
## Import Path
-First, import `Path` from `fastapi`:
+First, import `Path` from `fastapi`, and import `Annotated`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="3"
- {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
+ ```Python hl_lines="1 3"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="1 3"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="3-4"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="1"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
+ ```
+
+!!! info
+ FastAPI added support for `Annotated` (and started recommending it) in version 0.95.0.
+
+ If you have an older version, you would get errors when trying to use `Annotated`.
+
+ Make sure you [Upgrade the FastAPI version](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} to at least 0.95.1 before using `Annotated`.
+
## Declare metadata
You can declare all the same parameters as for `Query`.
For example, to declare a `title` metadata value for the path parameter `item_id` you can type:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="10"
- {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="8"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
+ ```
+
!!! note
A path parameter is always required as it has to be part of the path.
@@ -45,11 +100,14 @@ For example, to declare a `title` metadata value for the path parameter `item_id
## Order the parameters as you need
+!!! tip
+ This is probably not as important or necessary if you use `Annotated`.
+
Let's say that you want to declare the query parameter `q` as a required `str`.
And you don't need to declare anything else for that parameter, so you don't really need to use `Query`.
-But you still need to use `Path` for the `item_id` path parameter.
+But you still need to use `Path` for the `item_id` path parameter. And you don't want to use `Annotated` for some reason.
Python will complain if you put a value with a "default" before a value that doesn't have a "default".
@@ -59,13 +117,44 @@ It doesn't matter for **FastAPI**. It will detect the parameters by their names,
So, you can declare your function as:
-```Python hl_lines="7"
-{!../../../docs_src/path_params_numeric_validations/tutorial002.py!}
-```
+=== "Python 3.6 non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial002.py!}
+ ```
+
+But have in mind that if you use `Annotated`, you won't have this problem, it won't matter as you're not using the function parameter default values for `Query()` or `Path()`.
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial002_an.py!}
+ ```
## Order the parameters as you need, tricks
-If you want to declare the `q` query parameter without a `Query` nor any default value, and the path parameter `item_id` using `Path`, and have them in a different order, Python has a little special syntax for that.
+!!! tip
+ This is probably not as important or necessary if you use `Annotated`.
+
+Here's a **small trick** that can be handy, but you won't need it often.
+
+If you want to:
+
+* declare the `q` query parameter without a `Query` nor any default value
+* declare the path parameter `item_id` using `Path`
+* have them in a different order
+* not use `Annotated`
+
+...Python has a little special syntax for that.
Pass `*`, as the first parameter of the function.
@@ -75,15 +164,48 @@ Python won't do anything with that `*`, but it will know that all the following
{!../../../docs_src/path_params_numeric_validations/tutorial003.py!}
```
+### Better with `Annotated`
+
+Have in mind that if you use `Annotated`, as you are not using function parameter default values, you won't have this problem, and you probably won't need to use `*`.
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial003_an.py!}
+ ```
+
## Number validations: greater than or equal
With `Query` and `Path` (and others you'll see later) you can declare number constraints.
Here, with `ge=1`, `item_id` will need to be an integer number "`g`reater than or `e`qual" to `1`.
-```Python hl_lines="8"
-{!../../../docs_src/path_params_numeric_validations/tutorial004.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial004_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial004.py!}
+ ```
## Number validations: greater than and less than or equal
@@ -92,9 +214,26 @@ The same applies for:
* `gt`: `g`reater `t`han
* `le`: `l`ess than or `e`qual
-```Python hl_lines="9"
-{!../../../docs_src/path_params_numeric_validations/tutorial005.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial005_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial005.py!}
+ ```
## Number validations: floats, greater than and less than
@@ -106,9 +245,26 @@ So, `0.5` would be a valid value. But `0.0` or `0` would not.
And the same for lt
.
-```Python hl_lines="11"
-{!../../../docs_src/path_params_numeric_validations/tutorial006.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="13"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial006_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial006.py!}
+ ```
## Recap
diff --git a/docs/en/docs/tutorial/query-params-str-validations.md b/docs/en/docs/tutorial/query-params-str-validations.md
index 060e1d58a..c4b221cb1 100644
--- a/docs/en/docs/tutorial/query-params-str-validations.md
+++ b/docs/en/docs/tutorial/query-params-str-validations.md
@@ -4,16 +4,16 @@
Let's take this application as example:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="9"
- {!> ../../../docs_src/query_params_str_validations/tutorial001.py!}
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial001_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="7"
- {!> ../../../docs_src/query_params_str_validations/tutorial001_py310.py!}
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial001.py!}
```
The query parameter `q` is of type `Union[str, None]` (or `str | None` in Python 3.10), that means that it's of type `str` but could also be `None`, and indeed, the default value is `None`, so FastAPI will know it's not required.
@@ -27,39 +27,124 @@ The query parameter `q` is of type `Union[str, None]` (or `str | None` in Python
We are going to enforce that even though `q` is optional, whenever it is provided, **its length doesn't exceed 50 characters**.
-### Import `Query`
+### Import `Query` and `Annotated`
-To achieve that, first import `Query` from `fastapi`:
+To achieve that, first import:
-=== "Python 3.6 and above"
+* `Query` from `fastapi`
+* `Annotated` from `typing` (or from `typing_extensions` in Python below 3.9)
- ```Python hl_lines="3"
- {!> ../../../docs_src/query_params_str_validations/tutorial002.py!}
+=== "Python 3.10+"
+
+ In Python 3.9 or above, `Annotated` is part of the standard library, so you can import it from `typing`.
+
+ ```Python hl_lines="1 3"
+ {!> ../../../docs_src/query_params_str_validations/tutorial002_an_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="1"
- {!> ../../../docs_src/query_params_str_validations/tutorial002_py310.py!}
+ In versions of Python below Python 3.9 you import `Annotation` from `typing_extensions`.
+
+ It will already be installed with FastAPI.
+
+ ```Python hl_lines="3-4"
+ {!> ../../../docs_src/query_params_str_validations/tutorial002_an.py!}
+ ```
+
+!!! info
+ FastAPI added support for `Annotated` (and started recommending it) in version 0.95.0.
+
+ If you have an older version, you would get errors when trying to use `Annotated`.
+
+ Make sure you [Upgrade the FastAPI version](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} to at least 0.95.1 before using `Annotated`.
+
+## Use `Annotated` in the type for the `q` parameter
+
+Remember I told you before that `Annotated` can be used to add metadata to your parameters in the [Python Types Intro](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}?
+
+Now it's the time to use it with FastAPI. 🚀
+
+We had this type annotation:
+
+=== "Python 3.10+"
+
+ ```Python
+ q: str | None = None
+ ```
+
+=== "Python 3.6+"
+
+ ```Python
+ q: Union[str, None] = None
+ ```
+
+What we will do is wrap that with `Annotated`, so it becomes:
+
+=== "Python 3.10+"
+
+ ```Python
+ q: Annotated[str | None] = None
+ ```
+
+=== "Python 3.6+"
+
+ ```Python
+ q: Annotated[Union[str, None]] = None
```
-## Use `Query` as the default value
+Both of those versions mean the same thing, `q` is a parameter that can be a `str` or `None`, and by default, it is `None`.
-And now use it as the default value of your parameter, setting the parameter `max_length` to 50:
+Now let's jump to the fun stuff. 🎉
-=== "Python 3.6 and above"
+## Add `Query` to `Annotated` in the `q` parameter
+
+Now that we have this `Annotated` where we can put more metadata, add `Query` to it, and set the parameter `max_length` to 50:
+
+=== "Python 3.10+"
```Python hl_lines="9"
- {!> ../../../docs_src/query_params_str_validations/tutorial002.py!}
+ {!> ../../../docs_src/query_params_str_validations/tutorial002_an_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial002_an.py!}
```
-=== "Python 3.10 and above"
+Notice that the default value is still `None`, so the parameter is still optional.
+
+But now, having `Query(max_length=50)` inside of `Annotated`, we are telling FastAPI that we want it to extract this value from the query parameters (this would have been the default anyway 🤷) and that we want to have **additional validation** for this value (that's why we do this, to get the additional validation). 😎
+
+FastAPI will now:
+
+* **Validate** the data making sure that the max length is 50 characters
+* Show a **clear error** for the client when the data is not valid
+* **Document** the parameter in the OpenAPI schema *path operation* (so it will show up in the **automatic docs UI**)
+
+## Alternative (old) `Query` as the default value
+
+Previous versions of FastAPI (before 0.95.0) required you to use `Query` as the default value of your parameter, instead of putting it in `Annotated`, there's a high chance that you will see code using it around, so I'll explain it to you.
+
+!!! tip
+ For new code and whenever possible, use `Annotated` as explained above. There are multiple advantages (explained below) and no disadvantages. 🍰
+
+This is how you would use `Query()` as the default value of your function parameter, setting the parameter `max_length` to 50:
+
+=== "Python 3.10+"
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial002_py310.py!}
```
-As we have to replace the default value `None` in the function with `Query()`, we can now set the default value with the parameter `Query(default=None)`, it serves the same purpose of defining that default value.
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial002.py!}
+ ```
+
+As in this case (without using `Annotated`) we have to replace the default value `None` in the function with `Query()`, we now need to set the default value with the parameter `Query(default=None)`, it serves the same purpose of defining that default value (at least for FastAPI).
So:
@@ -67,7 +152,7 @@ So:
q: Union[str, None] = Query(default=None)
```
-...makes the parameter optional, the same as:
+...makes the parameter optional, with a default value of `None`, the same as:
```Python
q: Union[str, None] = None
@@ -79,7 +164,7 @@ And in Python 3.10 and above:
q: str | None = Query(default=None)
```
-...makes the parameter optional, the same as:
+...makes the parameter optional, with a default value of `None`, the same as:
```Python
q: str | None = None
@@ -112,38 +197,124 @@ q: Union[str, None] = Query(default=None, max_length=50)
This will validate the data, show a clear error when the data is not valid, and document the parameter in the OpenAPI schema *path operation*.
+### `Query` as the default value or in `Annotated`
+
+Have in mind that when using `Query` inside of `Annotated` you cannot use the `default` parameter for `Query`.
+
+Instead use the actual default value of the function parameter. Otherwise, it would be inconsistent.
+
+For example, this is not allowed:
+
+```Python
+q: Annotated[str, Query(default="rick")] = "morty"
+```
+
+...because it's not clear if the default value should be `"rick"` or `"morty"`.
+
+So, you would use (preferably):
+
+```Python
+q: Annotated[str, Query()] = "rick"
+```
+
+...or in older code bases you will find:
+
+```Python
+q: str = Query(default="rick")
+```
+
+### Advantages of `Annotated`
+
+**Using `Annotated` is recommended** instead of the default value in function parameters, it is **better** for multiple reasons. 🤓
+
+The **default** value of the **function parameter** is the **actual default** value, that's more intuitive with Python in general. 😌
+
+You could **call** that same function in **other places** without FastAPI, and it would **work as expected**. If there's a **required** parameter (without a default value), your **editor** will let you know with an error, **Python** will also complain if you run it without passing the required parameter.
+
+When you don't use `Annotated` and instead use the **(old) default value style**, if you call that function without FastAPI in **other place**, you have to **remember** to pass the arguments to the function for it to work correctly, otherwise the values will be different from what you expect (e.g. `QueryInfo` or something similar instead of `str`). And your editor won't complain, and Python won't complain running that function, only when the operations inside error out.
+
+Because `Annotated` can have more than one metadata annotation, you could now even use the same function with other tools, like Typer. 🚀
+
## Add more validations
You can also add a parameter `min_length`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="10"
- {!> ../../../docs_src/query_params_str_validations/tutorial003.py!}
+ {!> ../../../docs_src/query_params_str_validations/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/query_params_str_validations/tutorial003_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial003_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial003.py!}
+ ```
+
## Add regular expressions
You can define a regular expression that the parameter should match:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="11"
- {!> ../../../docs_src/query_params_str_validations/tutorial004.py!}
+ {!> ../../../docs_src/query_params_str_validations/tutorial004_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/query_params_str_validations/tutorial004_an_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/query_params_str_validations/tutorial004_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial004_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/query_params_str_validations/tutorial004.py!}
+ ```
+
This specific regular expression checks that the received parameter value:
* `^`: starts with the following characters, doesn't have characters before.
@@ -156,16 +327,33 @@ But whenever you need them and go and learn them, know that you can already use
## Default values
-The same way that you can pass `None` as the value for the `default` parameter, you can pass other values.
+You can, of course, use default values other than `None`.
Let's say that you want to declare the `q` query parameter to have a `min_length` of `3`, and to have a default value of `"fixedquery"`:
-```Python hl_lines="7"
-{!../../../docs_src/query_params_str_validations/tutorial005.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial005_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial005_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial005.py!}
+ ```
!!! note
- Having a default value also makes the parameter optional.
+ Having a default value of any type, including `None`, makes the parameter optional (not required).
## Make it required
@@ -183,23 +371,70 @@ q: Union[str, None] = None
But we are now declaring it with `Query`, for example like:
-```Python
-q: Union[str, None] = Query(default=None, min_length=3)
-```
+=== "Annotated"
+
+ ```Python
+ q: Annotated[Union[str, None], Query(min_length=3)] = None
+ ```
+
+=== "non-Annotated"
+
+ ```Python
+ q: Union[str, None] = Query(default=None, min_length=3)
+ ```
So, when you need to declare a value as required while using `Query`, you can simply not declare a default value:
-```Python hl_lines="7"
-{!../../../docs_src/query_params_str_validations/tutorial006.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006.py!}
+ ```
+
+ !!! tip
+ Notice that, even though in this case the `Query()` is used as the function parameter default value, we don't pass the `default=None` to `Query()`.
+
+ Still, probably better to use the `Annotated` version. 😉
### Required with Ellipsis (`...`)
-There's an alternative way to explicitly declare that a value is required. You can set the `default` parameter to the literal value `...`:
+There's an alternative way to explicitly declare that a value is required. You can set the default to the literal value `...`:
-```Python hl_lines="7"
-{!../../../docs_src/query_params_str_validations/tutorial006b.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006b_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006b_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006b.py!}
+ ```
!!! info
If you hadn't seen that `...` before: it is a special single value, it is part of Python and is called "Ellipsis".
@@ -212,20 +447,44 @@ This will let **FastAPI** know that this parameter is required.
You can declare that a parameter can accept `None`, but that it's still required. This would force clients to send a value, even if the value is `None`.
-To do that, you can declare that `None` is a valid type but still use `default=...`:
+To do that, you can declare that `None` is a valid type but still use `...` as the default:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="9"
- {!> ../../../docs_src/query_params_str_validations/tutorial006c.py!}
+ {!> ../../../docs_src/query_params_str_validations/tutorial006c_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006c_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006c_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial006c_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006c.py!}
+ ```
+
!!! tip
Pydantic, which is what powers all the data validation and serialization in FastAPI, has a special behavior when you use `Optional` or `Union[Something, None]` without a default value, you can read more about it in the Pydantic docs about Required Optional fields.
@@ -233,12 +492,29 @@ To do that, you can declare that `None` is a valid type but still use `default=.
If you feel uncomfortable using `...`, you can also import and use `Required` from Pydantic:
-```Python hl_lines="2 8"
-{!../../../docs_src/query_params_str_validations/tutorial006d.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="4 10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006d_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="2 9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006d_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="2 8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006d.py!}
+ ```
!!! tip
- Remember that in most of the cases, when something is required, you can simply omit the `default` parameter, so you normally don't have to use `...` nor `Required`.
+ Remember that in most of the cases, when something is required, you can simply omit the default, so you normally don't have to use `...` nor `Required`.
## Query parameter list / multiple values
@@ -246,24 +522,51 @@ When you define a query parameter explicitly with `Query` you can also declare i
For example, to declare a query parameter `q` that can appear multiple times in the URL, you can write:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="9"
- {!> ../../../docs_src/query_params_str_validations/tutorial011.py!}
+ {!> ../../../docs_src/query_params_str_validations/tutorial011_an_py310.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.9+"
```Python hl_lines="9"
- {!> ../../../docs_src/query_params_str_validations/tutorial011_py39.py!}
+ {!> ../../../docs_src/query_params_str_validations/tutorial011_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial011_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial011_py310.py!}
```
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial011_py39.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial011.py!}
+ ```
+
Then, with a URL like:
```
@@ -294,18 +597,36 @@ The interactive API docs will update accordingly, to allow multiple values:
And you can also define a default `list` of values if none are provided:
-=== "Python 3.6 and above"
+=== "Python 3.9+"
```Python hl_lines="9"
- {!> ../../../docs_src/query_params_str_validations/tutorial012.py!}
+ {!> ../../../docs_src/query_params_str_validations/tutorial012_an_py39.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial012_an.py!}
+ ```
+
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial012_py39.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial012.py!}
+ ```
+
If you go to:
```
@@ -327,9 +648,26 @@ the default of `q` will be: `["foo", "bar"]` and your response will be:
You can also use `list` directly instead of `List[str]` (or `list[str]` in Python 3.9+):
-```Python hl_lines="7"
-{!../../../docs_src/query_params_str_validations/tutorial013.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial013_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial013_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial013.py!}
+ ```
!!! note
Have in mind that in this case, FastAPI won't check the contents of the list.
@@ -349,32 +687,80 @@ That information will be included in the generated OpenAPI and used by the docum
You can add a `title`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="10"
- {!> ../../../docs_src/query_params_str_validations/tutorial007.py!}
+ {!> ../../../docs_src/query_params_str_validations/tutorial007_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial007_an_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/query_params_str_validations/tutorial007_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="8"
{!> ../../../docs_src/query_params_str_validations/tutorial007_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial007.py!}
+ ```
+
And a `description`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="13"
- {!> ../../../docs_src/query_params_str_validations/tutorial008.py!}
+ ```Python hl_lines="14"
+ {!> ../../../docs_src/query_params_str_validations/tutorial008_an_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.9+"
+
+ ```Python hl_lines="14"
+ {!> ../../../docs_src/query_params_str_validations/tutorial008_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="15"
+ {!> ../../../docs_src/query_params_str_validations/tutorial008_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="12"
{!> ../../../docs_src/query_params_str_validations/tutorial008_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="13"
+ {!> ../../../docs_src/query_params_str_validations/tutorial008.py!}
+ ```
+
## Alias parameters
Imagine that you want the parameter to be `item-query`.
@@ -393,18 +779,42 @@ But you still need it to be exactly `item-query`...
Then you can declare an `alias`, and that alias is what will be used to find the parameter value:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="9"
- {!> ../../../docs_src/query_params_str_validations/tutorial009.py!}
+ {!> ../../../docs_src/query_params_str_validations/tutorial009_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial009_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial009_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="7"
{!> ../../../docs_src/query_params_str_validations/tutorial009_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial009.py!}
+ ```
+
## Deprecating parameters
Now let's say you don't like this parameter anymore.
@@ -413,18 +823,42 @@ You have to leave it there a while because there are clients using it, but you w
Then pass the parameter `deprecated=True` to `Query`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="18"
- {!> ../../../docs_src/query_params_str_validations/tutorial010.py!}
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/query_params_str_validations/tutorial010_an_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.9+"
+
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/query_params_str_validations/tutorial010_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/query_params_str_validations/tutorial010_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="17"
{!> ../../../docs_src/query_params_str_validations/tutorial010_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/query_params_str_validations/tutorial010.py!}
+ ```
+
The docs will show it like this:
@@ -433,18 +867,42 @@ The docs will show it like this:
To exclude a query parameter from the generated OpenAPI schema (and thus, from the automatic documentation systems), set the parameter `include_in_schema` of `Query` to `False`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="10"
- {!> ../../../docs_src/query_params_str_validations/tutorial014.py!}
+ {!> ../../../docs_src/query_params_str_validations/tutorial014_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial014_an_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/query_params_str_validations/tutorial014_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="8"
{!> ../../../docs_src/query_params_str_validations/tutorial014_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial014.py!}
+ ```
+
## Recap
You can declare additional validations and metadata for your parameters.
diff --git a/docs/en/docs/tutorial/query-params.md b/docs/en/docs/tutorial/query-params.md
index eec55502a..0b74b10f8 100644
--- a/docs/en/docs/tutorial/query-params.md
+++ b/docs/en/docs/tutorial/query-params.md
@@ -63,16 +63,16 @@ The parameter values in your function will be:
The same way, you can declare optional query parameters, by setting their default to `None`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="9"
- {!> ../../../docs_src/query_params/tutorial002.py!}
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params/tutorial002_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="7"
- {!> ../../../docs_src/query_params/tutorial002_py310.py!}
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params/tutorial002.py!}
```
In this case, the function parameter `q` will be optional, and will be `None` by default.
@@ -84,16 +84,16 @@ In this case, the function parameter `q` will be optional, and will be `None` by
You can also declare `bool` types, and they will be converted:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="9"
- {!> ../../../docs_src/query_params/tutorial003.py!}
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params/tutorial003_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="7"
- {!> ../../../docs_src/query_params/tutorial003_py310.py!}
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params/tutorial003.py!}
```
In this case, if you go to:
@@ -137,16 +137,16 @@ And you don't have to declare them in any specific order.
They will be detected by name:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="8 10"
- {!> ../../../docs_src/query_params/tutorial004.py!}
+ ```Python hl_lines="6 8"
+ {!> ../../../docs_src/query_params/tutorial004_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="6 8"
- {!> ../../../docs_src/query_params/tutorial004_py310.py!}
+ ```Python hl_lines="8 10"
+ {!> ../../../docs_src/query_params/tutorial004.py!}
```
## Required query parameters
@@ -203,16 +203,16 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
And of course, you can define some parameters as required, some as having a default value, and some entirely optional:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="10"
- {!> ../../../docs_src/query_params/tutorial006.py!}
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params/tutorial006_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="8"
- {!> ../../../docs_src/query_params/tutorial006_py310.py!}
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params/tutorial006.py!}
```
In this case, there are 3 query parameters:
diff --git a/docs/en/docs/tutorial/request-files.md b/docs/en/docs/tutorial/request-files.md
index 783783c58..1fe1e7a33 100644
--- a/docs/en/docs/tutorial/request-files.md
+++ b/docs/en/docs/tutorial/request-files.md
@@ -13,17 +13,51 @@ You can define files to be uploaded by the client using `File`.
Import `File` and `UploadFile` from `fastapi`:
-```Python hl_lines="1"
-{!../../../docs_src/request_files/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/request_files/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/request_files/tutorial001_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/request_files/tutorial001.py!}
+ ```
## Define `File` Parameters
Create file parameters the same way you would for `Body` or `Form`:
-```Python hl_lines="7"
-{!../../../docs_src/request_files/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/request_files/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/request_files/tutorial001_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/request_files/tutorial001.py!}
+ ```
!!! info
`File` is a class that inherits directly from `Form`.
@@ -45,9 +79,26 @@ But there are several cases in which you might benefit from using `UploadFile`.
Define a file parameter with a type of `UploadFile`:
-```Python hl_lines="12"
-{!../../../docs_src/request_files/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="14"
+ {!> ../../../docs_src/request_files/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="13"
+ {!> ../../../docs_src/request_files/tutorial001_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/request_files/tutorial001.py!}
+ ```
Using `UploadFile` has several advantages over `bytes`:
@@ -118,25 +169,66 @@ The way HTML forms (``) sends the data to the server normally uses
You can make a file optional by using standard type annotations and setting a default value of `None`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="9 17"
- {!> ../../../docs_src/request_files/tutorial001_02.py!}
+ {!> ../../../docs_src/request_files/tutorial001_02_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9 17"
+ {!> ../../../docs_src/request_files/tutorial001_02_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10 18"
+ {!> ../../../docs_src/request_files/tutorial001_02_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
- ```Python hl_lines="7 14"
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7 15"
{!> ../../../docs_src/request_files/tutorial001_02_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9 17"
+ {!> ../../../docs_src/request_files/tutorial001_02.py!}
+ ```
+
## `UploadFile` with Additional Metadata
You can also use `File()` with `UploadFile`, for example, to set additional metadata:
-```Python hl_lines="13"
-{!../../../docs_src/request_files/tutorial001_03.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="9 15"
+ {!> ../../../docs_src/request_files/tutorial001_03_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8 14"
+ {!> ../../../docs_src/request_files/tutorial001_03_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7 13"
+ {!> ../../../docs_src/request_files/tutorial001_03.py!}
+ ```
## Multiple File Uploads
@@ -146,18 +238,36 @@ They would be associated to the same "form field" sent using "form data".
To use that, declare a list of `bytes` or `UploadFile`:
-=== "Python 3.6 and above"
+=== "Python 3.9+"
```Python hl_lines="10 15"
- {!> ../../../docs_src/request_files/tutorial002.py!}
+ {!> ../../../docs_src/request_files/tutorial002_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="11 16"
+ {!> ../../../docs_src/request_files/tutorial002_an.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="8 13"
{!> ../../../docs_src/request_files/tutorial002_py39.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="10 15"
+ {!> ../../../docs_src/request_files/tutorial002.py!}
+ ```
+
You will receive, as declared, a `list` of `bytes` or `UploadFile`s.
!!! note "Technical Details"
@@ -169,18 +279,36 @@ You will receive, as declared, a `list` of `bytes` or `UploadFile`s.
And the same way as before, you can use `File()` to set additional parameters, even for `UploadFile`:
-=== "Python 3.6 and above"
+=== "Python 3.9+"
- ```Python hl_lines="18"
- {!> ../../../docs_src/request_files/tutorial003.py!}
+ ```Python hl_lines="11 18-20"
+ {!> ../../../docs_src/request_files/tutorial003_an_py39.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.6+"
- ```Python hl_lines="16"
+ ```Python hl_lines="12 19-21"
+ {!> ../../../docs_src/request_files/tutorial003_an.py!}
+ ```
+
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9 16"
{!> ../../../docs_src/request_files/tutorial003_py39.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="11 18"
+ {!> ../../../docs_src/request_files/tutorial003.py!}
+ ```
+
## Recap
Use `File`, `bytes`, and `UploadFile` to declare files to be uploaded in the request, sent as form data.
diff --git a/docs/en/docs/tutorial/request-forms-and-files.md b/docs/en/docs/tutorial/request-forms-and-files.md
index 6844f8c65..1818946c4 100644
--- a/docs/en/docs/tutorial/request-forms-and-files.md
+++ b/docs/en/docs/tutorial/request-forms-and-files.md
@@ -9,17 +9,51 @@ You can define files and form fields at the same time using `File` and `Form`.
## Import `File` and `Form`
-```Python hl_lines="1"
-{!../../../docs_src/request_forms_and_files/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/request_forms_and_files/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/request_forms_and_files/tutorial001_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/request_forms_and_files/tutorial001.py!}
+ ```
## Define `File` and `Form` parameters
Create file and form parameters the same way you would for `Body` or `Query`:
-```Python hl_lines="8"
-{!../../../docs_src/request_forms_and_files/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="10-12"
+ {!> ../../../docs_src/request_forms_and_files/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9-11"
+ {!> ../../../docs_src/request_forms_and_files/tutorial001_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/request_forms_and_files/tutorial001.py!}
+ ```
The files and form fields will be uploaded as form data and you will receive the files and form fields.
diff --git a/docs/en/docs/tutorial/request-forms.md b/docs/en/docs/tutorial/request-forms.md
index 26922685a..5d441a614 100644
--- a/docs/en/docs/tutorial/request-forms.md
+++ b/docs/en/docs/tutorial/request-forms.md
@@ -11,17 +11,51 @@ When you need to receive form fields instead of JSON, you can use `Form`.
Import `Form` from `fastapi`:
-```Python hl_lines="1"
-{!../../../docs_src/request_forms/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/request_forms/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/request_forms/tutorial001_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/request_forms/tutorial001.py!}
+ ```
## Define `Form` parameters
Create form parameters the same way you would for `Body` or `Query`:
-```Python hl_lines="7"
-{!../../../docs_src/request_forms/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/request_forms/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/request_forms/tutorial001_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/request_forms/tutorial001.py!}
+ ```
For example, in one of the ways the OAuth2 specification can be used (called "password flow") it is required to send a `username` and `password` as form fields.
diff --git a/docs/en/docs/tutorial/response-model.md b/docs/en/docs/tutorial/response-model.md
index ab68314e8..2181cfb5a 100644
--- a/docs/en/docs/tutorial/response-model.md
+++ b/docs/en/docs/tutorial/response-model.md
@@ -1,6 +1,51 @@
-# Response Model
+# Response Model - Return Type
-You can declare the model used for the response with the parameter `response_model` in any of the *path operations*:
+You can declare the type used for the response by annotating the *path operation function* **return type**.
+
+You can use **type annotations** the same way you would for input data in function **parameters**, you can use Pydantic models, lists, dictionaries, scalar values like integers, booleans, etc.
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="16 21"
+ {!> ../../../docs_src/response_model/tutorial001_01_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="18 23"
+ {!> ../../../docs_src/response_model/tutorial001_01_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="18 23"
+ {!> ../../../docs_src/response_model/tutorial001_01.py!}
+ ```
+
+FastAPI will use this return type to:
+
+* **Validate** the returned data.
+ * If the data is invalid (e.g. you are missing a field), it means that *your* app code is broken, not returning what it should, and it will return a server error instead of returning incorrect data. This way you and your clients can be certain that they will receive the data and the data shape expected.
+* Add a **JSON Schema** for the response, in the OpenAPI *path operation*.
+ * This will be used by the **automatic docs**.
+ * It will also be used by automatic client code generation tools.
+
+But most importantly:
+
+* It will **limit and filter** the output data to what is defined in the return type.
+ * This is particularly important for **security**, we'll see more of that below.
+
+## `response_model` Parameter
+
+There are some cases where you need or want to return some data that is not exactly what the type declares.
+
+For example, you could want to **return a dictionary** or a database object, but **declare it as a Pydantic model**. This way the Pydantic model would do all the data documentation, validation, etc. for the object that you returned (e.g. a dictionary or database object).
+
+If you added the return type annotation, tools and editors would complain with a (correct) error telling you that your function is returning a type (e.g. a dict) that is different from what you declared (e.g. a Pydantic model).
+
+In those cases, you can use the *path operation decorator* parameter `response_model` instead of the return type.
+
+You can use the `response_model` parameter in any of the *path operations*:
* `@app.get()`
* `@app.post()`
@@ -8,57 +53,58 @@ You can declare the model used for the response with the parameter `response_mod
* `@app.delete()`
* etc.
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="17"
- {!> ../../../docs_src/response_model/tutorial001.py!}
+ ```Python hl_lines="17 22 24-27"
+ {!> ../../../docs_src/response_model/tutorial001_py310.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.9+"
- ```Python hl_lines="17"
+ ```Python hl_lines="17 22 24-27"
{!> ../../../docs_src/response_model/tutorial001_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="15"
- {!> ../../../docs_src/response_model/tutorial001_py310.py!}
+ ```Python hl_lines="17 22 24-27"
+ {!> ../../../docs_src/response_model/tutorial001.py!}
```
!!! note
Notice that `response_model` is a parameter of the "decorator" method (`get`, `post`, etc). Not of your *path operation function*, like all the parameters and body.
-It receives the same type you would declare for a Pydantic model attribute, so, it can be a Pydantic model, but it can also be, e.g. a `list` of Pydantic models, like `List[Item]`.
+`response_model` receives the same type you would declare for a Pydantic model field, so, it can be a Pydantic model, but it can also be, e.g. a `list` of Pydantic models, like `List[Item]`.
+
+FastAPI will use this `response_model` to do all the data documentation, validation, etc. and also to **convert and filter the output data** to its type declaration.
-FastAPI will use this `response_model` to:
+!!! tip
+ If you have strict type checks in your editor, mypy, etc, you can declare the function return type as `Any`.
-* Convert the output data to its type declaration.
-* Validate the data.
-* Add a JSON Schema for the response, in the OpenAPI *path operation*.
-* Will be used by the automatic documentation systems.
+ That way you tell the editor that you are intentionally returning anything. But FastAPI will still do the data documentation, validation, filtering, etc. with the `response_model`.
-But most importantly:
+### `response_model` Priority
-* Will limit the output data to that of the model. We'll see how that's important below.
+If you declare both a return type and a `response_model`, the `response_model` will take priority and be used by FastAPI.
-!!! note "Technical Details"
- The response model is declared in this parameter instead of as a function return type annotation, because the path function may not actually return that response model but rather return a `dict`, database object or some other model, and then use the `response_model` to perform the field limiting and serialization.
+This way you can add correct type annotations to your functions even when you are returning a type different than the response model, to be used by the editor and tools like mypy. And still you can have FastAPI do the data validation, documentation, etc. using the `response_model`.
+
+You can also use `response_model=None` to disable creating a response model for that *path operation*, you might need to do it if you are adding type annotations for things that are not valid Pydantic fields, you will see an example of that in one of the sections below.
## Return the same input data
Here we are declaring a `UserIn` model, it will contain a plaintext password:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="9 11"
- {!> ../../../docs_src/response_model/tutorial002.py!}
+ ```Python hl_lines="7 9"
+ {!> ../../../docs_src/response_model/tutorial002_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="7 9"
- {!> ../../../docs_src/response_model/tutorial002_py310.py!}
+ ```Python hl_lines="9 11"
+ {!> ../../../docs_src/response_model/tutorial002.py!}
```
!!! info
@@ -69,72 +115,126 @@ Here we are declaring a `UserIn` model, it will contain a plaintext password:
And we are using this model to declare our input and the same model to declare our output:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="17-18"
- {!> ../../../docs_src/response_model/tutorial002.py!}
+ ```Python hl_lines="16"
+ {!> ../../../docs_src/response_model/tutorial002_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="15-16"
- {!> ../../../docs_src/response_model/tutorial002_py310.py!}
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/response_model/tutorial002.py!}
```
Now, whenever a browser is creating a user with a password, the API will return the same password in the response.
-In this case, it might not be a problem, because the user themself is sending the password.
+In this case, it might not be a problem, because it's the same user sending the password.
But if we use the same model for another *path operation*, we could be sending our user's passwords to every client.
!!! danger
- Never store the plain password of a user or send it in a response.
+ Never store the plain password of a user or send it in a response like this, unless you know all the caveats and you know what you are doing.
## Add an output model
We can instead create an input model with the plaintext password and an output model without it:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="9 11 16"
- {!> ../../../docs_src/response_model/tutorial003.py!}
+ {!> ../../../docs_src/response_model/tutorial003_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="7 9 14"
- {!> ../../../docs_src/response_model/tutorial003_py310.py!}
+ ```Python hl_lines="9 11 16"
+ {!> ../../../docs_src/response_model/tutorial003.py!}
```
Here, even though our *path operation function* is returning the same input user that contains the password:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
+
+ ```Python hl_lines="24"
+ {!> ../../../docs_src/response_model/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.6+"
```Python hl_lines="24"
{!> ../../../docs_src/response_model/tutorial003.py!}
```
-=== "Python 3.10 and above"
+...we declared the `response_model` to be our model `UserOut`, that doesn't include the password:
+
+=== "Python 3.10+"
```Python hl_lines="22"
{!> ../../../docs_src/response_model/tutorial003_py310.py!}
```
-...we declared the `response_model` to be our model `UserOut`, that doesn't include the password:
-
-=== "Python 3.6 and above"
+=== "Python 3.6+"
```Python hl_lines="22"
{!> ../../../docs_src/response_model/tutorial003.py!}
```
-=== "Python 3.10 and above"
+So, **FastAPI** will take care of filtering out all the data that is not declared in the output model (using Pydantic).
- ```Python hl_lines="20"
- {!> ../../../docs_src/response_model/tutorial003_py310.py!}
+### `response_model` or Return Type
+
+In this case, because the two models are different, if we annotated the function return type as `UserOut`, the editor and tools would complain that we are returning an invalid type, as those are different classes.
+
+That's why in this example we have to declare it in the `response_model` parameter.
+
+...but continue reading below to see how to overcome that.
+
+## Return Type and Data Filtering
+
+Let's continue from the previous example. We wanted to **annotate the function with one type** but return something that includes **more data**.
+
+We want FastAPI to keep **filtering** the data using the response model.
+
+In the previous example, because the classes were different, we had to use the `response_model` parameter. But that also means that we don't get the support from the editor and tools checking the function return type.
+
+But in most of the cases where we need to do something like this, we want the model just to **filter/remove** some of the data as in this example.
+
+And in those cases, we can use classes and inheritance to take advantage of function **type annotations** to get better support in the editor and tools, and still get the FastAPI **data filtering**.
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="7-10 13-14 18"
+ {!> ../../../docs_src/response_model/tutorial003_01_py310.py!}
```
-So, **FastAPI** will take care of filtering out all the data that is not declared in the output model (using Pydantic).
+=== "Python 3.6+"
+
+ ```Python hl_lines="9-13 15-16 20"
+ {!> ../../../docs_src/response_model/tutorial003_01.py!}
+ ```
+
+With this, we get tooling support, from editors and mypy as this code is correct in terms of types, but we also get the data filtering from FastAPI.
+
+How does this work? Let's check that out. 🤓
+
+### Type Annotations and Tooling
+
+First let's see how editors, mypy and other tools would see this.
+
+`BaseUser` has the base fields. Then `UserIn` inherits from `BaseUser` and adds the `password` field, so, it will include all the fields from both models.
+
+We annotate the function return type as `BaseUser`, but we are actually returning a `UserIn` instance.
+
+The editor, mypy, and other tools won't complain about this because, in typing terms, `UserIn` is a subclass of `BaseUser`, which means it's a *valid* type when what is expected is anything that is a `BaseUser`.
+
+### FastAPI Data Filtering
+
+Now, for FastAPI, it will see the return type and make sure that what you return includes **only** the fields that are declared in the type.
+
+FastAPI does several things internally with Pydantic to make sure that those same rules of class inheritance are not used for the returned data filtering, otherwise you could end up returning much more data than what you expected.
+
+This way, you can get the best of both worlds: type annotations with **tooling support** and **data filtering**.
## See it in the docs
@@ -146,26 +246,94 @@ And both models will be used for the interactive API documentation:
+## Other Return Type Annotations
+
+There might be cases where you return something that is not a valid Pydantic field and you annotate it in the function, only to get the support provided by tooling (the editor, mypy, etc).
+
+### Return a Response Directly
+
+The most common case would be [returning a Response directly as explained later in the advanced docs](../advanced/response-directly.md){.internal-link target=_blank}.
+
+```Python hl_lines="8 10-11"
+{!> ../../../docs_src/response_model/tutorial003_02.py!}
+```
+
+This simple case is handled automatically by FastAPI because the return type annotation is the class (or a subclass) of `Response`.
+
+And tools will also be happy because both `RedirectResponse` and `JSONResponse` are subclasses of `Response`, so the type annotation is correct.
+
+### Annotate a Response Subclass
+
+You can also use a subclass of `Response` in the type annotation:
+
+```Python hl_lines="8-9"
+{!> ../../../docs_src/response_model/tutorial003_03.py!}
+```
+
+This will also work because `RedirectResponse` is a subclass of `Response`, and FastAPI will automatically handle this simple case.
+
+### Invalid Return Type Annotations
+
+But when you return some other arbitrary object that is not a valid Pydantic type (e.g. a database object) and you annotate it like that in the function, FastAPI will try to create a Pydantic response model from that type annotation, and will fail.
+
+The same would happen if you had something like a union between different types where one or more of them are not valid Pydantic types, for example this would fail 💥:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/response_model/tutorial003_04_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/response_model/tutorial003_04.py!}
+ ```
+
+...this fails because the type annotation is not a Pydantic type and is not just a single `Response` class or subclass, it's a union (any of the two) between a `Response` and a `dict`.
+
+### Disable Response Model
+
+Continuing from the example above, you might not want to have the default data validation, documentation, filtering, etc. that is performed by FastAPI.
+
+But you might want to still keep the return type annotation in the function to get the support from tools like editors and type checkers (e.g. mypy).
+
+In this case, you can disable the response model generation by setting `response_model=None`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/response_model/tutorial003_05_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/response_model/tutorial003_05.py!}
+ ```
+
+This will make FastAPI skip the response model generation and that way you can have any return type annotations you need without it affecting your FastAPI application. 🤓
+
## Response Model encoding parameters
Your response model could have default values, like:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="11 13-14"
- {!> ../../../docs_src/response_model/tutorial004.py!}
+ ```Python hl_lines="9 11-12"
+ {!> ../../../docs_src/response_model/tutorial004_py310.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.9+"
```Python hl_lines="11 13-14"
{!> ../../../docs_src/response_model/tutorial004_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="9 11-12"
- {!> ../../../docs_src/response_model/tutorial004_py310.py!}
+ ```Python hl_lines="11 13-14"
+ {!> ../../../docs_src/response_model/tutorial004.py!}
```
* `description: Union[str, None] = None` (or `str | None = None` in Python 3.10) has a default of `None`.
@@ -180,22 +348,22 @@ For example, if you have models with many optional attributes in a NoSQL databas
You can set the *path operation decorator* parameter `response_model_exclude_unset=True`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="24"
- {!> ../../../docs_src/response_model/tutorial004.py!}
+ ```Python hl_lines="22"
+ {!> ../../../docs_src/response_model/tutorial004_py310.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.9+"
```Python hl_lines="24"
{!> ../../../docs_src/response_model/tutorial004_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="22"
- {!> ../../../docs_src/response_model/tutorial004_py310.py!}
+ ```Python hl_lines="24"
+ {!> ../../../docs_src/response_model/tutorial004.py!}
```
and those default values won't be included in the response, only the values actually set.
@@ -273,16 +441,16 @@ This can be used as a quick shortcut if you have only one Pydantic model and wan
This also applies to `response_model_by_alias` that works similarly.
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="31 37"
- {!> ../../../docs_src/response_model/tutorial005.py!}
+ ```Python hl_lines="29 35"
+ {!> ../../../docs_src/response_model/tutorial005_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="29 35"
- {!> ../../../docs_src/response_model/tutorial005_py310.py!}
+ ```Python hl_lines="31 37"
+ {!> ../../../docs_src/response_model/tutorial005.py!}
```
!!! tip
@@ -294,16 +462,16 @@ This can be used as a quick shortcut if you have only one Pydantic model and wan
If you forget to use a `set` and use a `list` or `tuple` instead, FastAPI will still convert it to a `set` and it will work correctly:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="31 37"
- {!> ../../../docs_src/response_model/tutorial006.py!}
+ ```Python hl_lines="29 35"
+ {!> ../../../docs_src/response_model/tutorial006_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="29 35"
- {!> ../../../docs_src/response_model/tutorial006_py310.py!}
+ ```Python hl_lines="31 37"
+ {!> ../../../docs_src/response_model/tutorial006.py!}
```
## Recap
diff --git a/docs/en/docs/tutorial/schema-extra-example.md b/docs/en/docs/tutorial/schema-extra-example.md
index 94347018d..5312254d9 100644
--- a/docs/en/docs/tutorial/schema-extra-example.md
+++ b/docs/en/docs/tutorial/schema-extra-example.md
@@ -8,16 +8,16 @@ Here are several ways to do it.
You can declare an `example` for a Pydantic model using `Config` and `schema_extra`, as described in Pydantic's docs: Schema customization:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="15-23"
- {!> ../../../docs_src/schema_extra_example/tutorial001.py!}
+ ```Python hl_lines="13-21"
+ {!> ../../../docs_src/schema_extra_example/tutorial001_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="13-21"
- {!> ../../../docs_src/schema_extra_example/tutorial001_py310.py!}
+ ```Python hl_lines="15-23"
+ {!> ../../../docs_src/schema_extra_example/tutorial001.py!}
```
That extra info will be added as-is to the output **JSON Schema** for that model, and it will be used in the API docs.
@@ -33,16 +33,16 @@ When using `Field()` with Pydantic models, you can also declare extra info for t
You can use this to add `example` for each field:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="4 10-13"
- {!> ../../../docs_src/schema_extra_example/tutorial002.py!}
+ ```Python hl_lines="2 8-11"
+ {!> ../../../docs_src/schema_extra_example/tutorial002_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="2 8-11"
- {!> ../../../docs_src/schema_extra_example/tutorial002_py310.py!}
+ ```Python hl_lines="4 10-13"
+ {!> ../../../docs_src/schema_extra_example/tutorial002.py!}
```
!!! warning
@@ -66,18 +66,39 @@ you can also declare a data `example` or a group of `examples` with additional i
Here we pass an `example` of the data expected in `Body()`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="20-25"
- {!> ../../../docs_src/schema_extra_example/tutorial003.py!}
+ ```Python hl_lines="22-27"
+ {!> ../../../docs_src/schema_extra_example/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="22-27"
+ {!> ../../../docs_src/schema_extra_example/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="23-28"
+ {!> ../../../docs_src/schema_extra_example/tutorial003_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
```Python hl_lines="18-23"
{!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="20-25"
+ {!> ../../../docs_src/schema_extra_example/tutorial003.py!}
+ ```
+
### Example in the docs UI
With any of the methods above it would look like this in the `/docs`:
@@ -97,18 +118,39 @@ Each specific example `dict` in the `examples` can contain:
* `value`: This is the actual example shown, e.g. a `dict`.
* `externalValue`: alternative to `value`, a URL pointing to the example. Although this might not be supported by as many tools as `value`.
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="21-47"
- {!> ../../../docs_src/schema_extra_example/tutorial004.py!}
+ ```Python hl_lines="23-49"
+ {!> ../../../docs_src/schema_extra_example/tutorial004_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="23-49"
+ {!> ../../../docs_src/schema_extra_example/tutorial004_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="24-50"
+ {!> ../../../docs_src/schema_extra_example/tutorial004_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
```Python hl_lines="19-45"
{!> ../../../docs_src/schema_extra_example/tutorial004_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="21-47"
+ {!> ../../../docs_src/schema_extra_example/tutorial004.py!}
+ ```
+
### Examples in the docs UI
With `examples` added to `Body()` the `/docs` would look like:
diff --git a/docs/en/docs/tutorial/security/first-steps.md b/docs/en/docs/tutorial/security/first-steps.md
index 45ffaab90..5765cf2d6 100644
--- a/docs/en/docs/tutorial/security/first-steps.md
+++ b/docs/en/docs/tutorial/security/first-steps.md
@@ -20,9 +20,27 @@ Let's first just use the code and see how it works, and then we'll come back to
Copy the example in a file `main.py`:
-```Python
-{!../../../docs_src/security/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python
+ {!> ../../../docs_src/security/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python
+ {!> ../../../docs_src/security/tutorial001_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python
+ {!> ../../../docs_src/security/tutorial001.py!}
+ ```
+
## Run it
@@ -116,9 +134,26 @@ In this example we are going to use **OAuth2**, with the **Password** flow, usin
When we create an instance of the `OAuth2PasswordBearer` class we pass in the `tokenUrl` parameter. This parameter contains the URL that the client (the frontend running in the user's browser) will use to send the `username` and `password` in order to get a token.
-```Python hl_lines="6"
-{!../../../docs_src/security/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/security/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/security/tutorial001_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="6"
+ {!> ../../../docs_src/security/tutorial001.py!}
+ ```
!!! tip
Here `tokenUrl="token"` refers to a relative URL `token` that we haven't created yet. As it's a relative URL, it's equivalent to `./token`.
@@ -150,9 +185,26 @@ So, it can be used with `Depends`.
Now you can pass that `oauth2_scheme` in a dependency with `Depends`.
-```Python hl_lines="10"
-{!../../../docs_src/security/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/security/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/security/tutorial001_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/security/tutorial001.py!}
+ ```
This dependency will provide a `str` that is assigned to the parameter `token` of the *path operation function*.
diff --git a/docs/en/docs/tutorial/security/get-current-user.md b/docs/en/docs/tutorial/security/get-current-user.md
index 13e867216..1a8c5d9a8 100644
--- a/docs/en/docs/tutorial/security/get-current-user.md
+++ b/docs/en/docs/tutorial/security/get-current-user.md
@@ -2,9 +2,26 @@
In the previous chapter the security system (which is based on the dependency injection system) was giving the *path operation function* a `token` as a `str`:
-```Python hl_lines="10"
-{!../../../docs_src/security/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/security/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/security/tutorial001_an.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/security/tutorial001.py!}
+ ```
But that is still not that useful.
@@ -16,18 +33,42 @@ First, let's create a Pydantic user model.
The same way we use Pydantic to declare bodies, we can use it anywhere else:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="5 12-16"
- {!> ../../../docs_src/security/tutorial002.py!}
+ {!> ../../../docs_src/security/tutorial002_an_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.9+"
+
+ ```Python hl_lines="5 12-16"
+ {!> ../../../docs_src/security/tutorial002_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="5 13-17"
+ {!> ../../../docs_src/security/tutorial002_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="3 10-14"
{!> ../../../docs_src/security/tutorial002_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="5 12-16"
+ {!> ../../../docs_src/security/tutorial002.py!}
+ ```
+
## Create a `get_current_user` dependency
Let's create a dependency `get_current_user`.
@@ -38,50 +79,122 @@ Remember that dependencies can have sub-dependencies?
The same as we were doing before in the *path operation* directly, our new dependency `get_current_user` will receive a `token` as a `str` from the sub-dependency `oauth2_scheme`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="25"
- {!> ../../../docs_src/security/tutorial002.py!}
+ {!> ../../../docs_src/security/tutorial002_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="25"
+ {!> ../../../docs_src/security/tutorial002_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="26"
+ {!> ../../../docs_src/security/tutorial002_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="23"
{!> ../../../docs_src/security/tutorial002_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="25"
+ {!> ../../../docs_src/security/tutorial002.py!}
+ ```
+
## Get the user
`get_current_user` will use a (fake) utility function we created, that takes a token as a `str` and returns our Pydantic `User` model:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="19-22 26-27"
- {!> ../../../docs_src/security/tutorial002.py!}
+ {!> ../../../docs_src/security/tutorial002_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="19-22 26-27"
+ {!> ../../../docs_src/security/tutorial002_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="20-23 27-28"
+ {!> ../../../docs_src/security/tutorial002_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="17-20 24-25"
{!> ../../../docs_src/security/tutorial002_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="19-22 26-27"
+ {!> ../../../docs_src/security/tutorial002.py!}
+ ```
+
## Inject the current user
So now we can use the same `Depends` with our `get_current_user` in the *path operation*:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="31"
- {!> ../../../docs_src/security/tutorial002.py!}
+ {!> ../../../docs_src/security/tutorial002_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="31"
+ {!> ../../../docs_src/security/tutorial002_an_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
+
+ ```Python hl_lines="32"
+ {!> ../../../docs_src/security/tutorial002_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="29"
{!> ../../../docs_src/security/tutorial002_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="31"
+ {!> ../../../docs_src/security/tutorial002.py!}
+ ```
+
Notice that we declare the type of `current_user` as the Pydantic model `User`.
This will help us inside of the function with all the completion and type checks.
@@ -128,18 +241,42 @@ And all of them (or any portion of them that you want) can take the advantage of
And all these thousands of *path operations* can be as small as 3 lines:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="30-32"
- {!> ../../../docs_src/security/tutorial002.py!}
+ {!> ../../../docs_src/security/tutorial002_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="30-32"
+ {!> ../../../docs_src/security/tutorial002_an_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
+
+ ```Python hl_lines="31-33"
+ {!> ../../../docs_src/security/tutorial002_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="28-30"
{!> ../../../docs_src/security/tutorial002_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="30-32"
+ {!> ../../../docs_src/security/tutorial002.py!}
+ ```
+
## Recap
You can now get the current user directly in your *path operation function*.
diff --git a/docs/en/docs/tutorial/security/oauth2-jwt.md b/docs/en/docs/tutorial/security/oauth2-jwt.md
index 41f00fd41..deb722b96 100644
--- a/docs/en/docs/tutorial/security/oauth2-jwt.md
+++ b/docs/en/docs/tutorial/security/oauth2-jwt.md
@@ -109,18 +109,42 @@ And another utility to verify if a received password matches the hash stored.
And another one to authenticate and return a user.
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="7 48 55-56 59-60 69-75"
- {!> ../../../docs_src/security/tutorial004.py!}
+ {!> ../../../docs_src/security/tutorial004_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="7 48 55-56 59-60 69-75"
+ {!> ../../../docs_src/security/tutorial004_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="7 49 56-57 60-61 70-76"
+ {!> ../../../docs_src/security/tutorial004_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="6 47 54-55 58-59 68-74"
{!> ../../../docs_src/security/tutorial004_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7 48 55-56 59-60 69-75"
+ {!> ../../../docs_src/security/tutorial004.py!}
+ ```
+
!!! note
If you check the new (fake) database `fake_users_db`, you will see how the hashed password looks like now: `"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`.
@@ -152,18 +176,42 @@ Define a Pydantic Model that will be used in the token endpoint for the response
Create a utility function to generate a new access token.
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="6 12-14 28-30 78-86"
- {!> ../../../docs_src/security/tutorial004.py!}
+ {!> ../../../docs_src/security/tutorial004_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="6 12-14 28-30 78-86"
+ {!> ../../../docs_src/security/tutorial004_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="6 13-15 29-31 79-87"
+ {!> ../../../docs_src/security/tutorial004_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="5 11-13 27-29 77-85"
{!> ../../../docs_src/security/tutorial004_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="6 12-14 28-30 78-86"
+ {!> ../../../docs_src/security/tutorial004.py!}
+ ```
+
## Update the dependencies
Update `get_current_user` to receive the same token as before, but this time, using JWT tokens.
@@ -172,36 +220,84 @@ Decode the received token, verify it, and return the current user.
If the token is invalid, return an HTTP error right away.
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python hl_lines="89-106"
- {!> ../../../docs_src/security/tutorial004.py!}
+ {!> ../../../docs_src/security/tutorial004_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="89-106"
+ {!> ../../../docs_src/security/tutorial004_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="90-107"
+ {!> ../../../docs_src/security/tutorial004_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="88-105"
{!> ../../../docs_src/security/tutorial004_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="89-106"
+ {!> ../../../docs_src/security/tutorial004.py!}
+ ```
+
## Update the `/token` *path operation*
Create a `timedelta` with the expiration time of the token.
-Create a real JWT access token and return it.
+Create a real JWT access token and return it
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="115-128"
- {!> ../../../docs_src/security/tutorial004.py!}
+ ```Python hl_lines="117-132"
+ {!> ../../../docs_src/security/tutorial004_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="117-132"
+ {!> ../../../docs_src/security/tutorial004_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="118-133"
+ {!> ../../../docs_src/security/tutorial004_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="114-127"
{!> ../../../docs_src/security/tutorial004_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="115-128"
+ {!> ../../../docs_src/security/tutorial004.py!}
+ ```
+
### Technical details about the JWT "subject" `sub`
The JWT specification says that there's a key `sub`, with the subject of the token.
diff --git a/docs/en/docs/tutorial/security/simple-oauth2.md b/docs/en/docs/tutorial/security/simple-oauth2.md
index 505b223b1..abcf6b667 100644
--- a/docs/en/docs/tutorial/security/simple-oauth2.md
+++ b/docs/en/docs/tutorial/security/simple-oauth2.md
@@ -49,18 +49,42 @@ Now let's use the utilities provided by **FastAPI** to handle this.
First, import `OAuth2PasswordRequestForm`, and use it as a dependency with `Depends` in the *path operation* for `/token`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="4 76"
- {!> ../../../docs_src/security/tutorial003.py!}
+ ```Python hl_lines="4 78"
+ {!> ../../../docs_src/security/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="4 78"
+ {!> ../../../docs_src/security/tutorial003_an_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
+
+ ```Python hl_lines="4 79"
+ {!> ../../../docs_src/security/tutorial003_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="2 74"
{!> ../../../docs_src/security/tutorial003_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="4 76"
+ {!> ../../../docs_src/security/tutorial003.py!}
+ ```
+
`OAuth2PasswordRequestForm` is a class dependency that declares a form body with:
* The `username`.
@@ -98,18 +122,42 @@ If there is no such user, we return an error saying "incorrect username or passw
For the error, we use the exception `HTTPException`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="3 77-79"
- {!> ../../../docs_src/security/tutorial003.py!}
+ ```Python hl_lines="3 79-81"
+ {!> ../../../docs_src/security/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="3 79-81"
+ {!> ../../../docs_src/security/tutorial003_an_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
+
+ ```Python hl_lines="3 80-82"
+ {!> ../../../docs_src/security/tutorial003_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="1 75-77"
{!> ../../../docs_src/security/tutorial003_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="3 77-79"
+ {!> ../../../docs_src/security/tutorial003.py!}
+ ```
+
### Check the password
At this point we have the user data from our database, but we haven't checked the password.
@@ -134,18 +182,42 @@ If your database is stolen, the thief won't have your users' plaintext passwords
So, the thief won't be able to try to use those same passwords in another system (as many users use the same password everywhere, this would be dangerous).
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="80-83"
- {!> ../../../docs_src/security/tutorial003.py!}
+ ```Python hl_lines="82-85"
+ {!> ../../../docs_src/security/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="82-85"
+ {!> ../../../docs_src/security/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="83-86"
+ {!> ../../../docs_src/security/tutorial003_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="78-81"
{!> ../../../docs_src/security/tutorial003_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="80-83"
+ {!> ../../../docs_src/security/tutorial003.py!}
+ ```
+
#### About `**user_dict`
`UserInDB(**user_dict)` means:
@@ -180,18 +252,42 @@ For this simple example, we are going to just be completely insecure and return
But for now, let's focus on the specific details we need.
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="85"
- {!> ../../../docs_src/security/tutorial003.py!}
+ ```Python hl_lines="87"
+ {!> ../../../docs_src/security/tutorial003_an_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.9+"
+
+ ```Python hl_lines="87"
+ {!> ../../../docs_src/security/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="88"
+ {!> ../../../docs_src/security/tutorial003_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python hl_lines="83"
{!> ../../../docs_src/security/tutorial003_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="85"
+ {!> ../../../docs_src/security/tutorial003.py!}
+ ```
+
!!! tip
By the spec, you should return a JSON with an `access_token` and a `token_type`, the same as in this example.
@@ -213,18 +309,42 @@ Both of these dependencies will just return an HTTP error if the user doesn't ex
So, in our endpoint, we will only get a user if the user exists, was correctly authenticated, and is active:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="58-66 69-72 90"
- {!> ../../../docs_src/security/tutorial003.py!}
+ ```Python hl_lines="58-66 69-74 94"
+ {!> ../../../docs_src/security/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="58-66 69-74 94"
+ {!> ../../../docs_src/security/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="59-67 70-75 95"
+ {!> ../../../docs_src/security/tutorial003_an.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
- ```Python hl_lines="55-64 67-70 88"
+ ```Python hl_lines="56-64 67-70 88"
{!> ../../../docs_src/security/tutorial003_py310.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="58-66 69-72 90"
+ {!> ../../../docs_src/security/tutorial003.py!}
+ ```
+
!!! info
The additional header `WWW-Authenticate` with value `Bearer` we are returning here is also part of the spec.
diff --git a/docs/en/docs/tutorial/sql-databases.md b/docs/en/docs/tutorial/sql-databases.md
index 5ccaf05ec..fd66c5add 100644
--- a/docs/en/docs/tutorial/sql-databases.md
+++ b/docs/en/docs/tutorial/sql-databases.md
@@ -262,22 +262,22 @@ So, the user will also have a `password` when creating it.
But for security, the `password` won't be in other Pydantic *models*, for example, it won't be sent from the API when reading a user.
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="3 6-8 11-12 23-24 27-28"
- {!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
+ ```Python hl_lines="1 4-6 9-10 21-22 25-26"
+ {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.9+"
```Python hl_lines="3 6-8 11-12 23-24 27-28"
{!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="1 4-6 9-10 21-22 25-26"
- {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
+ ```Python hl_lines="3 6-8 11-12 23-24 27-28"
+ {!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
```
#### SQLAlchemy style and Pydantic style
@@ -306,22 +306,22 @@ The same way, when reading a user, we can now declare that `items` will contain
Not only the IDs of those items, but all the data that we defined in the Pydantic *model* for reading items: `Item`.
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="15-17 31-34"
- {!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
+ ```Python hl_lines="13-15 29-32"
+ {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.9+"
```Python hl_lines="15-17 31-34"
{!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="13-15 29-32"
- {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
+ ```Python hl_lines="15-17 31-34"
+ {!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
```
!!! tip
@@ -335,22 +335,22 @@ This ../../../docs_src/sql_databases/sql_app/schemas.py!}
+ ```Python hl_lines="13 17-18 29 34-35"
+ {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.9+"
```Python hl_lines="15 19-20 31 36-37"
{!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="13 17-18 29 34-35"
- {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
+ ```Python hl_lines="15 19-20 31 36-37"
+ {!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
```
!!! tip
@@ -481,16 +481,16 @@ And now in the file `sql_app/main.py` let's integrate and use all the other part
In a very simplistic way create the database tables:
-=== "Python 3.6 and above"
+=== "Python 3.9+"
- ```Python hl_lines="9"
- {!> ../../../docs_src/sql_databases/sql_app/main.py!}
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.6+"
- ```Python hl_lines="7"
- {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
#### Alembic Note
@@ -515,16 +515,16 @@ For that, we will create a new dependency with `yield`, as explained before in t
Our dependency will create a new SQLAlchemy `SessionLocal` that will be used in a single request, and then close it once the request is finished.
-=== "Python 3.6 and above"
+=== "Python 3.9+"
- ```Python hl_lines="15-20"
- {!> ../../../docs_src/sql_databases/sql_app/main.py!}
+ ```Python hl_lines="13-18"
+ {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.6+"
- ```Python hl_lines="13-18"
- {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
+ ```Python hl_lines="15-20"
+ {!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
!!! info
@@ -540,16 +540,16 @@ And then, when using the dependency in a *path operation function*, we declare i
This will then give us better editor support inside the *path operation function*, because the editor will know that the `db` parameter is of type `Session`:
-=== "Python 3.6 and above"
+=== "Python 3.9+"
- ```Python hl_lines="24 32 38 47 53"
- {!> ../../../docs_src/sql_databases/sql_app/main.py!}
+ ```Python hl_lines="22 30 36 45 51"
+ {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.6+"
- ```Python hl_lines="22 30 36 45 51"
- {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
+ ```Python hl_lines="24 32 38 47 53"
+ {!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
!!! info "Technical Details"
@@ -561,16 +561,16 @@ This will then give us better editor support inside the *path operation function
Now, finally, here's the standard **FastAPI** *path operations* code.
-=== "Python 3.6 and above"
+=== "Python 3.9+"
- ```Python hl_lines="23-28 31-34 37-42 45-49 52-55"
- {!> ../../../docs_src/sql_databases/sql_app/main.py!}
+ ```Python hl_lines="21-26 29-32 35-40 43-47 50-53"
+ {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.6+"
- ```Python hl_lines="21-26 29-32 35-40 43-47 50-53"
- {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
+ ```Python hl_lines="23-28 31-34 37-42 45-49 52-55"
+ {!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
We are creating the database session before each request in the dependency with `yield`, and then closing it afterwards.
@@ -654,22 +654,22 @@ For example, in a background task worker with ../../../docs_src/sql_databases/sql_app/schemas.py!}
+ {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.9+"
```Python
{!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
```Python
- {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
+ {!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
```
* `sql_app/crud.py`:
@@ -680,16 +680,16 @@ For example, in a background task worker with ../../../docs_src/sql_databases/sql_app/main.py!}
+ {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.6+"
```Python
- {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
+ {!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
## Check it
@@ -739,16 +739,16 @@ A "middleware" is basically a function that is always executed for each request,
The middleware we'll add (just a function) will create a new SQLAlchemy `SessionLocal` for each request, add it to the request and then close it once the request is finished.
-=== "Python 3.6 and above"
+=== "Python 3.9+"
- ```Python hl_lines="14-22"
- {!> ../../../docs_src/sql_databases/sql_app/alt_main.py!}
+ ```Python hl_lines="12-20"
+ {!> ../../../docs_src/sql_databases/sql_app_py39/alt_main.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.6+"
- ```Python hl_lines="12-20"
- {!> ../../../docs_src/sql_databases/sql_app_py39/alt_main.py!}
+ ```Python hl_lines="14-22"
+ {!> ../../../docs_src/sql_databases/sql_app/alt_main.py!}
```
!!! info
diff --git a/docs/en/docs/tutorial/testing.md b/docs/en/docs/tutorial/testing.md
index be07aab37..ec133a4d0 100644
--- a/docs/en/docs/tutorial/testing.md
+++ b/docs/en/docs/tutorial/testing.md
@@ -110,18 +110,42 @@ It has a `POST` operation that could return several errors.
Both *path operations* require an `X-Token` header.
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python
- {!> ../../../docs_src/app_testing/app_b/main.py!}
+ {!> ../../../docs_src/app_testing/app_b_an_py310/main.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python
+ {!> ../../../docs_src/app_testing/app_b_an_py39/main.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python
+ {!> ../../../docs_src/app_testing/app_b_an/main.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
```Python
{!> ../../../docs_src/app_testing/app_b_py310/main.py!}
```
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python
+ {!> ../../../docs_src/app_testing/app_b/main.py!}
+ ```
+
### Extended testing file
You could then update `test_main.py` with the extended tests:
diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml
index 69ad29624..b7cefee53 100644
--- a/docs/en/mkdocs.yml
+++ b/docs/en/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -187,7 +192,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -208,8 +213,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -218,6 +227,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -226,6 +237,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -238,6 +251,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html
index e9b9f60eb..9125b1d46 100644
--- a/docs/en/overrides/main.html
+++ b/docs/en/overrides/main.html
@@ -22,30 +22,12 @@
{% endblock %}
diff --git a/docs/es/mkdocs.yml b/docs/es/mkdocs.yml
index d1d6215b6..8152c91e3 100644
--- a/docs/es/mkdocs.yml
+++ b/docs/es/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -90,7 +95,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -111,8 +116,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -121,6 +130,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -129,6 +140,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -141,6 +154,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/fa/docs/index.md b/docs/fa/docs/index.md
index dfc4d24e3..ebaa8085a 100644
--- a/docs/fa/docs/index.md
+++ b/docs/fa/docs/index.md
@@ -143,7 +143,7 @@ $ pip install "uvicorn[standard]"
* فایلی به نام `main.py` با محتوای زیر ایجاد کنید :
```Python
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
diff --git a/docs/fa/mkdocs.yml b/docs/fa/mkdocs.yml
index 7c2fe5eab..2a966f664 100644
--- a/docs/fa/mkdocs.yml
+++ b/docs/fa/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -80,7 +85,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -101,8 +106,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -111,6 +120,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -119,6 +130,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -131,6 +144,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/fr/docs/advanced/index.md b/docs/fr/docs/advanced/index.md
new file mode 100644
index 000000000..41737889a
--- /dev/null
+++ b/docs/fr/docs/advanced/index.md
@@ -0,0 +1,24 @@
+# Guide de l'utilisateur avancé - Introduction
+
+## Caractéristiques supplémentaires
+
+Le [Tutoriel - Guide de l'utilisateur](../tutorial/){.internal-link target=_blank} devrait suffire à vous faire découvrir toutes les fonctionnalités principales de **FastAPI**.
+
+Dans les sections suivantes, vous verrez des options, configurations et fonctionnalités supplémentaires.
+
+!!! Note
+ Les sections de ce chapitre ne sont **pas nécessairement "avancées"**.
+
+ Et il est possible que pour votre cas d'utilisation, la solution se trouve dans l'un d'entre eux.
+
+## Lisez d'abord le didacticiel
+
+Vous pouvez utiliser la plupart des fonctionnalités de **FastAPI** grâce aux connaissances du [Tutoriel - Guide de l'utilisateur](../tutorial/){.internal-link target=_blank}.
+
+Et les sections suivantes supposent que vous l'avez lu et que vous en connaissez les idées principales.
+
+## Cours TestDriven.io
+
+Si vous souhaitez suivre un cours pour débutants avancés pour compléter cette section de la documentation, vous pouvez consulter : Développement piloté par les tests avec FastAPI et Docker par **TestDriven.io**.
+
+10 % de tous les bénéfices de ce cours sont reversés au développement de **FastAPI**. 🎉 😄
diff --git a/docs/fr/docs/advanced/path-operation-advanced-configuration.md b/docs/fr/docs/advanced/path-operation-advanced-configuration.md
new file mode 100644
index 000000000..ace9f19f9
--- /dev/null
+++ b/docs/fr/docs/advanced/path-operation-advanced-configuration.md
@@ -0,0 +1,168 @@
+# Configuration avancée des paramètres de chemin
+
+## ID d'opération OpenAPI
+
+!!! Attention
+ Si vous n'êtes pas un "expert" en OpenAPI, vous n'en avez probablement pas besoin.
+
+Dans OpenAPI, les chemins sont des ressources, tels que /users/ ou /items/, exposées par votre API, et les opérations sont les méthodes HTTP utilisées pour manipuler ces chemins, telles que GET, POST ou DELETE. Les operationId sont des chaînes uniques facultatives utilisées pour identifier une opération d'un chemin. Vous pouvez définir l'OpenAPI `operationId` à utiliser dans votre *opération de chemin* avec le paramètre `operation_id`.
+
+Vous devez vous assurer qu'il est unique pour chaque opération.
+
+```Python hl_lines="6"
+{!../../../docs_src/path_operation_advanced_configuration/tutorial001.py!}
+```
+
+### Utilisation du nom *path operation function* comme operationId
+
+Si vous souhaitez utiliser les noms de fonction de vos API comme `operationId`, vous pouvez les parcourir tous et remplacer chaque `operation_id` de l'*opération de chemin* en utilisant leur `APIRoute.name`.
+
+Vous devriez le faire après avoir ajouté toutes vos *paramètres de chemin*.
+
+```Python hl_lines="2 12-21 24"
+{!../../../docs_src/path_operation_advanced_configuration/tutorial002.py!}
+```
+
+!!! Astuce
+ Si vous appelez manuellement `app.openapi()`, vous devez mettre à jour les `operationId` avant.
+
+!!! Attention
+ Pour faire cela, vous devez vous assurer que chacun de vos *chemin* ait un nom unique.
+
+ Même s'ils se trouvent dans des modules différents (fichiers Python).
+
+## Exclusion d'OpenAPI
+
+Pour exclure un *chemin* du schéma OpenAPI généré (et donc des systèmes de documentation automatiques), utilisez le paramètre `include_in_schema` et assignez-lui la valeur `False` :
+
+```Python hl_lines="6"
+{!../../../docs_src/path_operation_advanced_configuration/tutorial003.py!}
+```
+
+## Description avancée de docstring
+
+Vous pouvez limiter le texte utilisé de la docstring d'une *fonction de chemin* qui sera affiché sur OpenAPI.
+
+L'ajout d'un `\f` (un caractère d'échappement "form feed") va permettre à **FastAPI** de tronquer la sortie utilisée pour OpenAPI à ce stade.
+
+Il n'apparaîtra pas dans la documentation, mais d'autres outils (tel que Sphinx) pourront utiliser le reste.
+
+```Python hl_lines="19-29"
+{!../../../docs_src/path_operation_advanced_configuration/tutorial004.py!}
+```
+
+## Réponses supplémentaires
+
+Vous avez probablement vu comment déclarer le `response_model` et le `status_code` pour une *opération de chemin*.
+
+Cela définit les métadonnées sur la réponse principale d'une *opération de chemin*.
+
+Vous pouvez également déclarer des réponses supplémentaires avec leurs modèles, codes de statut, etc.
+
+Il y a un chapitre entier ici dans la documentation à ce sujet, vous pouvez le lire sur [Réponses supplémentaires dans OpenAPI](./additional-responses.md){.internal-link target=_blank}.
+
+## OpenAPI supplémentaire
+
+Lorsque vous déclarez un *chemin* dans votre application, **FastAPI** génère automatiquement les métadonnées concernant ce *chemin* à inclure dans le schéma OpenAPI.
+
+!!! note "Détails techniques"
+ La spécification OpenAPI appelle ces métaonnées des Objets d'opération.
+
+Il contient toutes les informations sur le *chemin* et est utilisé pour générer automatiquement la documentation.
+
+Il inclut les `tags`, `parameters`, `requestBody`, `responses`, etc.
+
+Ce schéma OpenAPI spécifique aux *operations* est normalement généré automatiquement par **FastAPI**, mais vous pouvez également l'étendre.
+
+!!! Astuce
+ Si vous avez seulement besoin de déclarer des réponses supplémentaires, un moyen plus pratique de le faire est d'utiliser les [réponses supplémentaires dans OpenAPI](./additional-responses.md){.internal-link target=_blank}.
+
+Vous pouvez étendre le schéma OpenAPI pour une *opération de chemin* en utilisant le paramètre `openapi_extra`.
+
+### Extensions OpenAPI
+
+Cet `openapi_extra` peut être utile, par exemple, pour déclarer [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) :
+
+```Python hl_lines="6"
+{!../../../docs_src/path_operation_advanced_configuration/tutorial005.py!}
+```
+
+Si vous ouvrez la documentation automatique de l'API, votre extension apparaîtra au bas du *chemin* spécifique.
+
+
+
+Et dans le fichier openapi généré (`/openapi.json`), vous verrez également votre extension dans le cadre du *chemin* spécifique :
+
+```JSON hl_lines="22"
+{
+ "openapi": "3.0.2",
+ "info": {
+ "title": "FastAPI",
+ "version": "0.1.0"
+ },
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {}
+ }
+ }
+ }
+ },
+ "x-aperture-labs-portal": "blue"
+ }
+ }
+ }
+}
+```
+
+### Personnalisation du Schéma OpenAPI pour un chemin
+
+Le dictionnaire contenu dans la variable `openapi_extra` sera fusionné avec le schéma OpenAPI généré automatiquement pour l'*opération de chemin*.
+
+Ainsi, vous pouvez ajouter des données supplémentaires au schéma généré automatiquement.
+
+Par exemple, vous pouvez décider de lire et de valider la requête avec votre propre code, sans utiliser les fonctionnalités automatiques de validation proposée par Pydantic, mais vous pouvez toujours définir la requête dans le schéma OpenAPI.
+
+Vous pouvez le faire avec `openapi_extra` :
+
+```Python hl_lines="20-37 39-40"
+{!../../../docs_src/path_operation_advanced_configuration/tutorial006.py !}
+```
+
+Dans cet exemple, nous n'avons déclaré aucun modèle Pydantic. En fait, le corps de la requête n'est même pas parsé en tant que JSON, il est lu directement en tant que `bytes`, et la fonction `magic_data_reader()` serait chargé de l'analyser d'une manière ou d'une autre.
+
+Néanmoins, nous pouvons déclarer le schéma attendu pour le corps de la requête.
+
+### Type de contenu OpenAPI personnalisé
+
+En utilisant cette même astuce, vous pouvez utiliser un modèle Pydantic pour définir le schéma JSON qui est ensuite inclus dans la section de schéma OpenAPI personnalisée pour le *chemin* concerné.
+
+Et vous pouvez le faire même si le type de données dans la requête n'est pas au format JSON.
+
+Dans cet exemple, nous n'utilisons pas les fonctionnalités de FastAPI pour extraire le schéma JSON des modèles Pydantic ni la validation automatique pour JSON. En fait, nous déclarons le type de contenu de la requête en tant que YAML, et non JSON :
+
+```Python hl_lines="17-22 24"
+{!../../../docs_src/path_operation_advanced_configuration/tutorial007.py!}
+```
+
+Néanmoins, bien que nous n'utilisions pas la fonctionnalité par défaut, nous utilisons toujours un modèle Pydantic pour générer manuellement le schéma JSON pour les données que nous souhaitons recevoir en YAML.
+
+Ensuite, nous utilisons directement la requête et extrayons son contenu en tant qu'octets. Cela signifie que FastAPI n'essaiera même pas d'analyser le payload de la requête en tant que JSON.
+
+Et nous analysons directement ce contenu YAML, puis nous utilisons à nouveau le même modèle Pydantic pour valider le contenu YAML :
+
+```Python hl_lines="26-33"
+{!../../../docs_src/path_operation_advanced_configuration/tutorial007.py!}
+```
+
+!!! Astuce
+ Ici, nous réutilisons le même modèle Pydantic.
+
+ Mais nous aurions pu tout aussi bien pu le valider d'une autre manière.
diff --git a/docs/fr/docs/advanced/response-directly.md b/docs/fr/docs/advanced/response-directly.md
new file mode 100644
index 000000000..1c923fb82
--- /dev/null
+++ b/docs/fr/docs/advanced/response-directly.md
@@ -0,0 +1,63 @@
+# Renvoyer directement une réponse
+
+Lorsque vous créez une *opération de chemins* **FastAPI**, vous pouvez normalement retourner n'importe quelle donnée : un `dict`, une `list`, un modèle Pydantic, un modèle de base de données, etc.
+
+Par défaut, **FastAPI** convertirait automatiquement cette valeur de retour en JSON en utilisant le `jsonable_encoder` expliqué dans [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}.
+
+Ensuite, en arrière-plan, il mettra ces données JSON-compatible (par exemple un `dict`) à l'intérieur d'un `JSONResponse` qui sera utilisé pour envoyer la réponse au client.
+
+Mais vous pouvez retourner une `JSONResponse` directement à partir de vos *opérations de chemin*.
+
+Cela peut être utile, par exemple, pour retourner des en-têtes personnalisés ou des cookies.
+
+## Renvoyer une `Response`
+
+En fait, vous pouvez retourner n'importe quelle `Response` ou n'importe quelle sous-classe de celle-ci.
+
+!!! Note
+ `JSONResponse` est elle-même une sous-classe de `Response`.
+
+Et quand vous retournez une `Response`, **FastAPI** la transmet directement.
+
+Elle ne fera aucune conversion de données avec les modèles Pydantic, elle ne convertira pas le contenu en un type quelconque.
+
+Cela vous donne beaucoup de flexibilité. Vous pouvez retourner n'importe quel type de données, surcharger n'importe quelle déclaration ou validation de données.
+
+## Utiliser le `jsonable_encoder` dans une `Response`
+
+Parce que **FastAPI** n'apporte aucune modification à une `Response` que vous retournez, vous devez vous assurer que son contenu est prêt à être utilisé (sérialisable).
+
+Par exemple, vous ne pouvez pas mettre un modèle Pydantic dans une `JSONResponse` sans d'abord le convertir en un `dict` avec tous les types de données (comme `datetime`, `UUID`, etc.) convertis en types compatibles avec JSON.
+
+Pour ces cas, vous pouvez spécifier un appel à `jsonable_encoder` pour convertir vos données avant de les passer à une réponse :
+
+```Python hl_lines="6-7 21-22"
+{!../../../docs_src/response_directly/tutorial001.py!}
+```
+
+!!! note "Détails techniques"
+ Vous pouvez aussi utiliser `from starlette.responses import JSONResponse`.
+
+ **FastAPI** fournit le même objet `starlette.responses` que `fastapi.responses` juste par commodité pour le développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette.
+
+## Renvoyer une `Response` personnalisée
+
+L'exemple ci-dessus montre toutes les parties dont vous avez besoin, mais il n'est pas encore très utile, car vous auriez pu retourner l'`item` directement, et **FastAPI** l'aurait mis dans une `JSONResponse` pour vous, en le convertissant en `dict`, etc. Tout cela par défaut.
+
+Maintenant, voyons comment vous pourriez utiliser cela pour retourner une réponse personnalisée.
+
+Disons que vous voulez retourner une réponse XML.
+
+Vous pouvez mettre votre contenu XML dans une chaîne de caractères, la placer dans une `Response`, et la retourner :
+
+```Python hl_lines="1 18"
+{!../../../docs_src/response_directly/tutorial002.py!}
+```
+
+## Notes
+
+Lorsque vous renvoyez une `Response` directement, ses données ne sont pas validées, converties (sérialisées), ni documentées automatiquement.
+
+Mais vous pouvez toujours les documenter comme décrit dans [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}.
+
+Vous pouvez voir dans les sections suivantes comment utiliser/déclarer ces `Response`s personnalisées tout en conservant la conversion automatique des données, la documentation, etc.
diff --git a/docs/fr/docs/deployment/manually.md b/docs/fr/docs/deployment/manually.md
new file mode 100644
index 000000000..c53e2db67
--- /dev/null
+++ b/docs/fr/docs/deployment/manually.md
@@ -0,0 +1,153 @@
+# Exécuter un serveur manuellement - Uvicorn
+
+La principale chose dont vous avez besoin pour exécuter une application **FastAPI** sur une machine serveur distante est un programme serveur ASGI tel que **Uvicorn**.
+
+Il existe 3 principales alternatives :
+
+* Uvicorn : un serveur ASGI haute performance.
+* Hypercorn : un serveur
+ ASGI compatible avec HTTP/2 et Trio entre autres fonctionnalités.
+* Daphne : le serveur ASGI
+ conçu pour Django Channels.
+
+## Machine serveur et programme serveur
+
+Il y a un petit détail sur les noms à garder à l'esprit. 💡
+
+Le mot "**serveur**" est couramment utilisé pour désigner à la fois l'ordinateur distant/cloud (la machine physique ou virtuelle) et également le programme qui s'exécute sur cette machine (par exemple, Uvicorn).
+
+Gardez cela à l'esprit lorsque vous lisez "serveur" en général, cela pourrait faire référence à l'une de ces deux choses.
+
+Lorsqu'on se réfère à la machine distante, il est courant de l'appeler **serveur**, mais aussi **machine**, **VM** (machine virtuelle), **nœud**. Tout cela fait référence à un type de machine distante, exécutant Linux, en règle générale, sur laquelle vous exécutez des programmes.
+
+
+## Installer le programme serveur
+
+Vous pouvez installer un serveur compatible ASGI avec :
+
+=== "Uvicorn"
+
+ * Uvicorn, un serveur ASGI rapide comme l'éclair, basé sur uvloop et httptools.
+
+
+
+ ```console
+ $ pip install "uvicorn[standard]"
+
+ ---> 100%
+ ```
+
+
+
+ !!! tip "Astuce"
+ En ajoutant `standard`, Uvicorn va installer et utiliser quelques dépendances supplémentaires recommandées.
+
+ Cela inclut `uvloop`, le remplaçant performant de `asyncio`, qui fournit le gros gain de performance en matière de concurrence.
+
+=== "Hypercorn"
+
+ * Hypercorn, un serveur ASGI également compatible avec HTTP/2.
+
+
+
+ ```console
+ $ pip install hypercorn
+
+ ---> 100%
+ ```
+
+
+
+ ...ou tout autre serveur ASGI.
+
+## Exécutez le programme serveur
+
+Vous pouvez ensuite exécuter votre application de la même manière que vous l'avez fait dans les tutoriels, mais sans l'option `--reload`, par exemple :
+
+=== "Uvicorn"
+
+
+
+ ```console
+ $ uvicorn main:app --host 0.0.0.0 --port 80
+
+ INFO: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
+ ```
+
+
+
+=== "Hypercorn"
+
+
+
+ ```console
+ $ hypercorn main:app --bind 0.0.0.0:80
+
+ Running on 0.0.0.0:8080 over http (CTRL + C to quit)
+ ```
+
+
+
+!!! warning
+ N'oubliez pas de supprimer l'option `--reload` si vous l'utilisiez.
+
+ L'option `--reload` consomme beaucoup plus de ressources, est plus instable, etc.
+
+ Cela aide beaucoup pendant le **développement**, mais vous **ne devriez pas** l'utiliser en **production**.
+
+## Hypercorn avec Trio
+
+Starlette et **FastAPI** sont basés sur
+AnyIO, qui les rend
+compatibles avec asyncio, de la bibliothèque standard Python et
+Trio.
+
+Néanmoins, Uvicorn n'est actuellement compatible qu'avec asyncio, et il utilise normalement `uvloop`, le remplaçant hautes performances de `asyncio`.
+
+Mais si vous souhaitez utiliser directement **Trio**, vous pouvez utiliser **Hypercorn** car il le prend en charge. ✨
+
+### Installer Hypercorn avec Trio
+
+Vous devez d'abord installer Hypercorn avec le support Trio :
+
+
+
+```console
+$ pip install "hypercorn[trio]"
+---> 100%
+```
+
+
+
+### Exécuter avec Trio
+
+Ensuite, vous pouvez passer l'option de ligne de commande `--worker-class` avec la valeur `trio` :
+
+
+
+```console
+$ hypercorn main:app --worker-class trio
+```
+
+
+
+Et cela démarrera Hypercorn avec votre application en utilisant Trio comme backend.
+
+Vous pouvez désormais utiliser Trio en interne dans votre application. Ou mieux encore, vous pouvez utiliser AnyIO pour que votre code reste compatible avec Trio et asyncio. 🎉
+
+## Concepts de déploiement
+
+Ces exemples lancent le programme serveur (e.g. Uvicorn), démarrant **un seul processus**, sur toutes les IPs (`0.0.
+0.0`) sur un port prédéfini (par example, `80`).
+
+C'est l'idée de base. Mais vous vous préoccuperez probablement de certains concepts supplémentaires, tels que ... :
+
+* la sécurité - HTTPS
+* l'exécution au démarrage
+* les redémarrages
+* la réplication (le nombre de processus en cours d'exécution)
+* la mémoire
+* les étapes précédant le démarrage
+
+Je vous en dirai plus sur chacun de ces concepts, sur la façon de les aborder, et donnerai quelques exemples concrets avec des stratégies pour les traiter dans les prochains chapitres. 🚀
diff --git a/docs/fr/docs/index.md b/docs/fr/docs/index.md
index e7fb9947d..5ee8b462f 100644
--- a/docs/fr/docs/index.md
+++ b/docs/fr/docs/index.md
@@ -1,48 +1,46 @@
-
-{!../../../docs/missing-translation.md!}
-
-
- FastAPI framework, high performance, easy to learn, fast to code, ready for production
+ Framework FastAPI, haute performance, facile à apprendre, rapide à coder, prêt pour la production
-
-
+
+
-
-
+
+
+
+
+
---
-**Documentation**: https://fastapi.tiangolo.com
+**Documentation** : https://fastapi.tiangolo.com
-**Source Code**: https://github.com/tiangolo/fastapi
+**Code Source** : https://github.com/tiangolo/fastapi
---
-FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.6+ based on standard Python type hints.
+FastAPI est un framework web moderne et rapide (haute performance) pour la création d'API avec Python 3.7+, basé sur les annotations de type standard de Python.
-The key features are:
+Les principales fonctionnalités sont :
-* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance).
+* **Rapidité** : De très hautes performances, au niveau de **NodeJS** et **Go** (grâce à Starlette et Pydantic). [L'un des frameworks Python les plus rapides](#performance).
+* **Rapide à coder** : Augmente la vitesse de développement des fonctionnalités d'environ 200 % à 300 %. *
+* **Moins de bugs** : Réduit d'environ 40 % les erreurs induites par le développeur. *
+* **Intuitif** : Excellente compatibilité avec les IDE. Complétion complète. Moins de temps passé à déboguer.
+* **Facile** : Conçu pour être facile à utiliser et à apprendre. Moins de temps passé à lire la documentation.
+* **Concis** : Diminue la duplication de code. De nombreuses fonctionnalités liées à la déclaration de chaque paramètre. Moins de bugs.
+* **Robuste** : Obtenez un code prêt pour la production. Avec une documentation interactive automatique.
+* **Basé sur des normes** : Basé sur (et entièrement compatible avec) les standards ouverts pour les APIs : OpenAPI (précédemment connu sous le nom de Swagger) et JSON Schema.
-* **Fast to code**: Increase the speed to develop features by about 200% to 300%. *
-* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. *
-* **Intuitive**: Great editor support. Completion everywhere. Less time debugging.
-* **Easy**: Designed to be easy to use and learn. Less time reading docs.
-* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
-* **Robust**: Get production-ready code. With automatic interactive documentation.
-* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema.
-
-* estimation based on tests on an internal development team, building production applications.
+* estimation basée sur des tests d'une équipe de développement interne, construisant des applications de production.
## Sponsors
@@ -63,60 +61,66 @@ The key features are:
## Opinions
-"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._"
+"_[...] J'utilise beaucoup **FastAPI** ces derniers temps. [...] Je prévois de l'utiliser dans mon équipe pour tous les **services de ML chez Microsoft**. Certains d'entre eux seront intégrés dans le coeur de **Windows** et dans certains produits **Office**._"
Kabir Khan -
Microsoft (ref)
---
-"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_"
+"_Nous avons adopté la bibliothèque **FastAPI** pour créer un serveur **REST** qui peut être interrogé pour obtenir des **prédictions**. [pour Ludwig]_"
-Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala -
Uber (ref)
+Piero Molino, Yaroslav Dudin et Sai Sumanth Miryala -
Uber (ref)
---
-"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_"
+"_**Netflix** a le plaisir d'annoncer la sortie en open-source de notre framework d'orchestration de **gestion de crise** : **Dispatch** ! [construit avec **FastAPI**]_"
Kevin Glisson, Marc Vilanova, Forest Monsen -
Netflix (ref)
---
-"_I’m over the moon excited about **FastAPI**. It’s so fun!_"
+"_Je suis très enthousiaste à propos de **FastAPI**. C'est un bonheur !_"
-
+
---
-"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._"
+"_Honnêtement, ce que vous avez construit a l'air super solide et élégant. A bien des égards, c'est comme ça que je voulais que **Hug** soit - c'est vraiment inspirant de voir quelqu'un construire ça._"
-
+
---
-"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_"
+"_Si vous cherchez à apprendre un **framework moderne** pour créer des APIs REST, regardez **FastAPI** [...] C'est rapide, facile à utiliser et à apprendre [...]_"
+
+"_Nous sommes passés à **FastAPI** pour nos **APIs** [...] Je pense que vous l'aimerez [...]_"
+
+
+
+---
-"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_"
+"_Si quelqu'un cherche à construire une API Python de production, je recommande vivement **FastAPI**. Il est **bien conçu**, **simple à utiliser** et **très évolutif**. Il est devenu un **composant clé** dans notre stratégie de développement API first et il est à l'origine de nombreux automatismes et services tels que notre ingénieur virtuel TAC._"
-
+Deon Pillsbury -
Cisco (ref)
---
-## **Typer**, the FastAPI of CLIs
+## **Typer**, le FastAPI des CLI
-If you are building a CLI app to be used in the terminal instead of a web API, check out **Typer**.
+Si vous souhaitez construire une application CLI utilisable dans un terminal au lieu d'une API web, regardez **Typer**.
-**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀
+**Typer** est le petit frère de FastAPI. Et il est destiné à être le **FastAPI des CLI**. ⌨️ 🚀
-## Requirements
+## Prérequis
Python 3.7+
-FastAPI stands on the shoulders of giants:
+FastAPI repose sur les épaules de géants :
-* Starlette for the web parts.
-* Pydantic for the data parts.
+* Starlette pour les parties web.
+* Pydantic pour les parties données.
## Installation
@@ -130,7 +134,7 @@ $ pip install fastapi
-You will also need an ASGI server, for production such as Uvicorn or Hypercorn.
+Vous aurez également besoin d'un serveur ASGI pour la production tel que Uvicorn ou Hypercorn.
@@ -142,11 +146,11 @@ $ pip install "uvicorn[standard]"
-## Example
+## Exemple
-### Create it
+### Créez
-* Create a file `main.py` with:
+* Créez un fichier `main.py` avec :
```Python
from typing import Union
@@ -167,11 +171,11 @@ def read_item(item_id: int, q: Union[str, None] = None):
```
-Or use async def
...
+Ou utilisez async def
...
-If your code uses `async` / `await`, use `async def`:
+Si votre code utilise `async` / `await`, utilisez `async def` :
-```Python hl_lines="9 14"
+```Python hl_lines="9 14"
from typing import Union
from fastapi import FastAPI
@@ -189,15 +193,15 @@ async def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
-**Note**:
+**Note**
-If you don't know, check the _"In a hurry?"_ section about `async` and `await` in the docs.
+Si vous n'êtes pas familier avec cette notion, consultez la section _"Vous êtes pressés ?"_ à propos de `async` et `await` dans la documentation.
-### Run it
+### Lancez
-Run the server with:
+Lancez le serveur avec :
@@ -214,56 +218,56 @@ INFO: Application startup complete.
-About the command uvicorn main:app --reload
...
+À propos de la commande uvicorn main:app --reload
...
-The command `uvicorn main:app` refers to:
+La commande `uvicorn main:app` fait référence à :
-* `main`: the file `main.py` (the Python "module").
-* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.
-* `--reload`: make the server restart after code changes. Only do this for development.
+* `main` : le fichier `main.py` (le "module" Python).
+* `app` : l'objet créé à l'intérieur de `main.py` avec la ligne `app = FastAPI()`.
+* `--reload` : fait redémarrer le serveur après des changements de code. À n'utiliser que pour le développement.
-### Check it
+### Vérifiez
-Open your browser at http://127.0.0.1:8000/items/5?q=somequery.
+Ouvrez votre navigateur à l'adresse http://127.0.0.1:8000/items/5?q=somequery.
-You will see the JSON response as:
+Vous obtenez alors cette réponse JSON :
```JSON
{"item_id": 5, "q": "somequery"}
```
-You already created an API that:
+Vous venez de créer une API qui :
-* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`.
-* Both _paths_ take `GET` operations (also known as HTTP _methods_).
-* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`.
-* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`.
+* Reçoit les requêtes HTTP pour les _chemins_ `/` et `/items/{item_id}`.
+* Les deux _chemins_ acceptent des opérations `GET` (également connu sous le nom de _méthodes_ HTTP).
+* Le _chemin_ `/items/{item_id}` a un _paramètre_ `item_id` qui doit être un `int`.
+* Le _chemin_ `/items/{item_id}` a un _paramètre de requête_ optionnel `q` de type `str`.
-### Interactive API docs
+### Documentation API interactive
-Now go to http://127.0.0.1:8000/docs.
+Maintenant, rendez-vous sur http://127.0.0.1:8000/docs.
-You will see the automatic interactive API documentation (provided by Swagger UI):
+Vous verrez la documentation interactive automatique de l'API (fournie par Swagger UI) :

-### Alternative API docs
+### Documentation API alternative
-And now, go to http://127.0.0.1:8000/redoc.
+Et maintenant, rendez-vous sur http://127.0.0.1:8000/redoc.
-You will see the alternative automatic documentation (provided by ReDoc):
+Vous verrez la documentation interactive automatique de l'API (fournie par ReDoc) :

-## Example upgrade
+## Exemple plus poussé
-Now modify the file `main.py` to receive a body from a `PUT` request.
+Maintenant, modifiez le fichier `main.py` pour recevoir le corps d'une requête `PUT`.
-Declare the body using standard Python types, thanks to Pydantic.
+Déclarez ce corps en utilisant les types Python standards, grâce à Pydantic.
-```Python hl_lines="4 9 10 11 12 25 26 27"
+```Python hl_lines="4 9-12 25-27"
from typing import Union
from fastapi import FastAPI
@@ -293,174 +297,173 @@ def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
```
-The server should reload automatically (because you added `--reload` to the `uvicorn` command above).
+Le serveur se recharge normalement automatiquement (car vous avez pensé à `--reload` dans la commande `uvicorn` ci-dessus).
-### Interactive API docs upgrade
+### Plus loin avec la documentation API interactive
-Now go to http://127.0.0.1:8000/docs.
+Maintenant, rendez-vous sur http://127.0.0.1:8000/docs.
-* The interactive API documentation will be automatically updated, including the new body:
+* La documentation interactive de l'API sera automatiquement mise à jour, y compris le nouveau corps de la requête :

-* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API:
+* Cliquez sur le bouton "Try it out", il vous permet de renseigner les paramètres et d'interagir directement avec l'API :

-* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen:
+* Cliquez ensuite sur le bouton "Execute", l'interface utilisateur communiquera avec votre API, enverra les paramètres, obtiendra les résultats et les affichera à l'écran :

-### Alternative API docs upgrade
+### Plus loin avec la documentation API alternative
-And now, go to http://127.0.0.1:8000/redoc.
+Et maintenant, rendez-vous sur http://127.0.0.1:8000/redoc.
-* The alternative documentation will also reflect the new query parameter and body:
+* La documentation alternative reflétera également le nouveau paramètre de requête et le nouveau corps :

-### Recap
+### En résumé
-In summary, you declare **once** the types of parameters, body, etc. as function parameters.
+En résumé, vous déclarez **une fois** les types de paramètres, le corps de la requête, etc. en tant que paramètres de fonction.
-You do that with standard modern Python types.
+Vous faites cela avec les types Python standard modernes.
-You don't have to learn a new syntax, the methods or classes of a specific library, etc.
+Vous n'avez pas à apprendre une nouvelle syntaxe, les méthodes ou les classes d'une bibliothèque spécifique, etc.
-Just standard **Python 3.6+**.
+Juste du **Python 3.7+** standard.
-For example, for an `int`:
+Par exemple, pour un `int`:
```Python
item_id: int
```
-or for a more complex `Item` model:
+ou pour un modèle `Item` plus complexe :
```Python
item: Item
```
-...and with that single declaration you get:
-
-* Editor support, including:
- * Completion.
- * Type checks.
-* Validation of data:
- * Automatic and clear errors when the data is invalid.
- * Validation even for deeply nested JSON objects.
-* Conversion of input data: coming from the network to Python data and types. Reading from:
- * JSON.
- * Path parameters.
- * Query parameters.
- * Cookies.
- * Headers.
- * Forms.
- * Files.
-* Conversion of output data: converting from Python data and types to network data (as JSON):
- * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc).
- * `datetime` objects.
- * `UUID` objects.
- * Database models.
- * ...and many more.
-* Automatic interactive API documentation, including 2 alternative user interfaces:
+... et avec cette déclaration unique, vous obtenez :
+
+* Une assistance dans votre IDE, notamment :
+ * la complétion.
+ * la vérification des types.
+* La validation des données :
+ * des erreurs automatiques et claires lorsque les données ne sont pas valides.
+ * une validation même pour les objets JSON profondément imbriqués.
+* Une conversion des données d'entrée : venant du réseau et allant vers les données et types de Python, permettant de lire :
+ * le JSON.
+ * les paramètres du chemin.
+ * les paramètres de la requête.
+ * les cookies.
+ * les en-têtes.
+ * les formulaires.
+ * les fichiers.
+* La conversion des données de sortie : conversion des données et types Python en données réseau (au format JSON), permettant de convertir :
+ * les types Python (`str`, `int`, `float`, `bool`, `list`, etc).
+ * les objets `datetime`.
+ * les objets `UUID`.
+ * les modèles de base de données.
+ * ... et beaucoup plus.
+* La documentation API interactive automatique, avec 2 interfaces utilisateur au choix :
* Swagger UI.
* ReDoc.
---
-Coming back to the previous code example, **FastAPI** will:
-
-* Validate that there is an `item_id` in the path for `GET` and `PUT` requests.
-* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests.
- * If it is not, the client will see a useful, clear error.
-* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests.
- * As the `q` parameter is declared with `= None`, it is optional.
- * Without the `None` it would be required (as is the body in the case with `PUT`).
-* For `PUT` requests to `/items/{item_id}`, Read the body as JSON:
- * Check that it has a required attribute `name` that should be a `str`.
- * Check that it has a required attribute `price` that has to be a `float`.
- * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present.
- * All this would also work for deeply nested JSON objects.
-* Convert from and to JSON automatically.
-* Document everything with OpenAPI, that can be used by:
- * Interactive documentation systems.
- * Automatic client code generation systems, for many languages.
-* Provide 2 interactive documentation web interfaces directly.
+Pour revenir à l'exemple de code précédent, **FastAPI** permet de :
+
+* Valider que `item_id` existe dans le chemin des requêtes `GET` et `PUT`.
+* Valider que `item_id` est de type `int` pour les requêtes `GET` et `PUT`.
+ * Si ce n'est pas le cas, le client voit une erreur utile et claire.
+* Vérifier qu'il existe un paramètre de requête facultatif nommé `q` (comme dans `http://127.0.0.1:8000/items/foo?q=somequery`) pour les requêtes `GET`.
+ * Puisque le paramètre `q` est déclaré avec `= None`, il est facultatif.
+ * Sans le `None`, il serait nécessaire (comme l'est le corps de la requête dans le cas du `PUT`).
+* Pour les requêtes `PUT` vers `/items/{item_id}`, de lire le corps en JSON :
+ * Vérifier qu'il a un attribut obligatoire `name` qui devrait être un `str`.
+ * Vérifier qu'il a un attribut obligatoire `prix` qui doit être un `float`.
+ * Vérifier qu'il a un attribut facultatif `is_offer`, qui devrait être un `bool`, s'il est présent.
+ * Tout cela fonctionnerait également pour les objets JSON profondément imbriqués.
+* Convertir de et vers JSON automatiquement.
+* Documenter tout avec OpenAPI, qui peut être utilisé par :
+ * Les systèmes de documentation interactifs.
+ * Les systèmes de génération automatique de code client, pour de nombreuses langues.
+* Fournir directement 2 interfaces web de documentation interactive.
---
-We just scratched the surface, but you already get the idea of how it all works.
+Nous n'avons fait qu'effleurer la surface, mais vous avez déjà une idée de la façon dont tout cela fonctionne.
-Try changing the line with:
+Essayez de changer la ligne contenant :
```Python
return {"item_name": item.name, "item_id": item_id}
```
-...from:
+... de :
```Python
... "item_name": item.name ...
```
-...to:
+... vers :
```Python
... "item_price": item.price ...
```
-...and see how your editor will auto-complete the attributes and know their types:
+... et voyez comment votre éditeur complétera automatiquement les attributs et connaîtra leurs types :
-
+
-For a more complete example including more features, see the Tutorial - User Guide.
+Pour un exemple plus complet comprenant plus de fonctionnalités, voir le Tutoriel - Guide utilisateur.
-**Spoiler alert**: the tutorial - user guide includes:
+**Spoiler alert** : le tutoriel - guide utilisateur inclut :
-* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**.
-* How to set **validation constraints** as `maximum_length` or `regex`.
-* A very powerful and easy to use **Dependency Injection** system.
-* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth.
-* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic).
-* Many extra features (thanks to Starlette) as:
+* Déclaration de **paramètres** provenant d'autres endroits différents comme : **en-têtes.**, **cookies**, **champs de formulaire** et **fichiers**.
+* L'utilisation de **contraintes de validation** comme `maximum_length` ou `regex`.
+* Un **systéme d'injection de dépendance ** très puissant et facile à utiliser .
+* Sécurité et authentification, y compris la prise en charge de **OAuth2** avec les **jetons JWT** et l'authentification **HTTP Basic**.
+* Des techniques plus avancées (mais tout aussi faciles) pour déclarer les **modèles JSON profondément imbriqués** (grâce à Pydantic).
+* Intégration de **GraphQL** avec Strawberry et d'autres bibliothèques.
+* D'obtenir de nombreuses fonctionnalités supplémentaires (grâce à Starlette) comme :
* **WebSockets**
- * **GraphQL**
- * extremely easy tests based on HTTPX and `pytest`
- * **CORS**
+ * de tester le code très facilement avec `requests` et `pytest`
+ * **CORS**
* **Cookie Sessions**
- * ...and more.
+ * ... et plus encore.
## Performance
-Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as one of the fastest Python frameworks available, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
+Les benchmarks TechEmpower indépendants montrent que les applications **FastAPI** s'exécutant sous Uvicorn sont parmi les frameworks existants en Python les plus rapides , juste derrière Starlette et Uvicorn (utilisés en interne par FastAPI). (*)
-To understand more about it, see the section Benchmarks.
+Pour en savoir plus, consultez la section Benchmarks.
-## Optional Dependencies
+## Dépendances facultatives
-Used by Pydantic:
+Utilisées par Pydantic:
-* ujson
- for faster JSON "parsing".
-* email_validator
- for email validation.
+* ujson
- pour un "décodage" JSON plus rapide.
+* email_validator
- pour la validation des adresses email.
-Used by Starlette:
+Utilisées par Starlette :
-* HTTPX
- Required if you want to use the `TestClient`.
-* jinja2
- Required if you want to use the default template configuration.
-* python-multipart
- Required if you want to support form "parsing", with `request.form()`.
-* itsdangerous
- Required for `SessionMiddleware` support.
-* pyyaml
- Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI).
-* graphene
- Required for `GraphQLApp` support.
-* ujson
- Required if you want to use `UJSONResponse`.
+* requests
- Obligatoire si vous souhaitez utiliser `TestClient`.
+* jinja2
- Obligatoire si vous souhaitez utiliser la configuration de template par defaut.
+* python-multipart
- Obligatoire si vous souhaitez supporter le "décodage" de formulaire avec `request.form()`.
+* itsdangerous
- Obligatoire pour la prise en charge de `SessionMiddleware`.
+* pyyaml
- Obligatoire pour le support `SchemaGenerator` de Starlette (vous n'en avez probablement pas besoin avec FastAPI).
+* ujson
- Obligatoire si vous souhaitez utiliser `UJSONResponse`.
-Used by FastAPI / Starlette:
+Utilisées par FastAPI / Starlette :
-* uvicorn
- for the server that loads and serves your application.
-* orjson
- Required if you want to use `ORJSONResponse`.
+* uvicorn
- Pour le serveur qui charge et sert votre application.
+* orjson
- Obligatoire si vous voulez utiliser `ORJSONResponse`.
-You can install all of these with `pip install fastapi[all]`.
+Vous pouvez tout installer avec `pip install fastapi[all]`.
-## License
+## Licence
-This project is licensed under the terms of the MIT license.
+Ce projet est soumis aux termes de la licence MIT.
diff --git a/docs/fr/docs/tutorial/debugging.md b/docs/fr/docs/tutorial/debugging.md
new file mode 100644
index 000000000..e58872d30
--- /dev/null
+++ b/docs/fr/docs/tutorial/debugging.md
@@ -0,0 +1,112 @@
+# Débogage
+
+Vous pouvez connecter le débogueur dans votre éditeur, par exemple avec Visual Studio Code ou PyCharm.
+
+## Faites appel à `uvicorn`
+
+Dans votre application FastAPI, importez et exécutez directement `uvicorn` :
+
+```Python hl_lines="1 15"
+{!../../../docs_src/debugging/tutorial001.py!}
+```
+
+### À propos de `__name__ == "__main__"`
+
+Le but principal de `__name__ == "__main__"` est d'avoir du code qui est exécuté lorsque votre fichier est appelé avec :
+
+
+
+```console
+$ python myapp.py
+```
+
+
+
+mais qui n'est pas appelé lorsqu'un autre fichier l'importe, comme dans :
+
+```Python
+from myapp import app
+```
+
+#### Pour davantage de détails
+
+Imaginons que votre fichier s'appelle `myapp.py`.
+
+Si vous l'exécutez avec :
+
+
+
+```console
+$ python myapp.py
+```
+
+
+
+alors la variable interne `__name__` de votre fichier, créée automatiquement par Python, aura pour valeur la chaîne de caractères `"__main__"`.
+
+Ainsi, la section :
+
+```Python
+ uvicorn.run(app, host="0.0.0.0", port=8000)
+```
+
+va s'exécuter.
+
+---
+
+Cela ne se produira pas si vous importez ce module (fichier).
+
+Par exemple, si vous avez un autre fichier `importer.py` qui contient :
+
+```Python
+from myapp import app
+
+# Code supplémentaire
+```
+
+dans ce cas, la variable automatique `__name__` à l'intérieur de `myapp.py` n'aura pas la valeur `"__main__"`.
+
+Ainsi, la ligne :
+
+```Python
+ uvicorn.run(app, host="0.0.0.0", port=8000)
+```
+
+ne sera pas exécutée.
+
+!!! info
+Pour plus d'informations, consultez la documentation officielle de Python.
+
+## Exécutez votre code avec votre débogueur
+
+Parce que vous exécutez le serveur Uvicorn directement depuis votre code, vous pouvez appeler votre programme Python (votre application FastAPI) directement depuis le débogueur.
+
+---
+
+Par exemple, dans Visual Studio Code, vous pouvez :
+
+- Cliquer sur l'onglet "Debug" de la barre d'activités de Visual Studio Code.
+- "Add configuration...".
+- Sélectionnez "Python".
+- Lancez le débogueur avec l'option "`Python: Current File (Integrated Terminal)`".
+
+Il démarrera alors le serveur avec votre code **FastAPI**, s'arrêtera à vos points d'arrêt, etc.
+
+Voici à quoi cela pourrait ressembler :
+
+
+
+---
+
+Si vous utilisez Pycharm, vous pouvez :
+
+- Ouvrir le menu "Run".
+- Sélectionnez l'option "Debug...".
+- Un menu contextuel s'affiche alors.
+- Sélectionnez le fichier à déboguer (dans ce cas, `main.py`).
+
+Il démarrera alors le serveur avec votre code **FastAPI**, s'arrêtera à vos points d'arrêt, etc.
+
+Voici à quoi cela pourrait ressembler :
+
+
diff --git a/docs/fr/mkdocs.yml b/docs/fr/mkdocs.yml
index 7dce4b127..0b73d3cae 100644
--- a/docs/fr/mkdocs.yml
+++ b/docs/fr/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -67,8 +72,12 @@ nav:
- tutorial/query-params.md
- tutorial/body.md
- tutorial/background-tasks.md
+ - tutorial/debugging.md
- Guide utilisateur avancé:
+ - advanced/index.md
+ - advanced/path-operation-advanced-configuration.md
- advanced/additional-status-codes.md
+ - advanced/response-directly.md
- advanced/additional-responses.md
- async.md
- Déploiement:
@@ -77,6 +86,7 @@ nav:
- deployment/https.md
- deployment/deta.md
- deployment/docker.md
+ - deployment/manually.md
- project-generation.md
- alternatives.md
- history-design-future.md
@@ -104,7 +114,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -125,8 +135,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -135,6 +149,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -143,6 +159,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -155,6 +173,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/he/mkdocs.yml b/docs/he/mkdocs.yml
index 3279099b5..b8a674812 100644
--- a/docs/he/mkdocs.yml
+++ b/docs/he/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -80,7 +85,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -101,8 +106,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -111,6 +120,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -119,6 +130,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -131,6 +144,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/hy/docs/index.md b/docs/hy/docs/index.md
new file mode 100644
index 000000000..cc82b33cf
--- /dev/null
+++ b/docs/hy/docs/index.md
@@ -0,0 +1,467 @@
+
+{!../../../docs/missing-translation.md!}
+
+
+
+
+
+
+ FastAPI framework, high performance, easy to learn, fast to code, ready for production
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+**Documentation**: https://fastapi.tiangolo.com
+
+**Source Code**: https://github.com/tiangolo/fastapi
+
+---
+
+FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints.
+
+The key features are:
+
+* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance).
+* **Fast to code**: Increase the speed to develop features by about 200% to 300%. *
+* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. *
+* **Intuitive**: Great editor support. Completion everywhere. Less time debugging.
+* **Easy**: Designed to be easy to use and learn. Less time reading docs.
+* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
+* **Robust**: Get production-ready code. With automatic interactive documentation.
+* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema.
+
+* estimation based on tests on an internal development team, building production applications.
+
+## Sponsors
+
+
+
+{% if sponsors %}
+{% for sponsor in sponsors.gold -%}
+
+{% endfor -%}
+{%- for sponsor in sponsors.silver -%}
+
+{% endfor %}
+{% endif %}
+
+
+
+Other sponsors
+
+## Opinions
+
+"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._"
+
+Kabir Khan -
Microsoft (ref)
+
+---
+
+"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_"
+
+Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala -
Uber (ref)
+
+---
+
+"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_"
+
+Kevin Glisson, Marc Vilanova, Forest Monsen -
Netflix (ref)
+
+---
+
+"_I’m over the moon excited about **FastAPI**. It’s so fun!_"
+
+
+
+---
+
+"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._"
+
+
+
+---
+
+"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_"
+
+"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_"
+
+
+
+---
+
+## **Typer**, the FastAPI of CLIs
+
+
+
+If you are building a CLI app to be used in the terminal instead of a web API, check out **Typer**.
+
+**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀
+
+## Requirements
+
+Python 3.7+
+
+FastAPI stands on the shoulders of giants:
+
+* Starlette for the web parts.
+* Pydantic for the data parts.
+
+## Installation
+
+
+
+```console
+$ pip install fastapi
+
+---> 100%
+```
+
+
+
+You will also need an ASGI server, for production such as Uvicorn or Hypercorn.
+
+
+
+```console
+$ pip install "uvicorn[standard]"
+
+---> 100%
+```
+
+
+
+## Example
+
+### Create it
+
+* Create a file `main.py` with:
+
+```Python
+from typing import Union
+
+from fastapi import FastAPI
+
+app = FastAPI()
+
+
+@app.get("/")
+def read_root():
+ return {"Hello": "World"}
+
+
+@app.get("/items/{item_id}")
+def read_item(item_id: int, q: Union[str, None] = None):
+ return {"item_id": item_id, "q": q}
+```
+
+
+Or use async def
...
+
+If your code uses `async` / `await`, use `async def`:
+
+```Python hl_lines="9 14"
+from typing import Union
+
+from fastapi import FastAPI
+
+app = FastAPI()
+
+
+@app.get("/")
+async def read_root():
+ return {"Hello": "World"}
+
+
+@app.get("/items/{item_id}")
+async def read_item(item_id: int, q: Union[str, None] = None):
+ return {"item_id": item_id, "q": q}
+```
+
+**Note**:
+
+If you don't know, check the _"In a hurry?"_ section about `async` and `await` in the docs.
+
+
+
+### Run it
+
+Run the server with:
+
+
+
+```console
+$ uvicorn main:app --reload
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+INFO: Started reloader process [28720]
+INFO: Started server process [28722]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+```
+
+
+
+
+About the command uvicorn main:app --reload
...
+
+The command `uvicorn main:app` refers to:
+
+* `main`: the file `main.py` (the Python "module").
+* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.
+* `--reload`: make the server restart after code changes. Only do this for development.
+
+
+
+### Check it
+
+Open your browser at http://127.0.0.1:8000/items/5?q=somequery.
+
+You will see the JSON response as:
+
+```JSON
+{"item_id": 5, "q": "somequery"}
+```
+
+You already created an API that:
+
+* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`.
+* Both _paths_ take `GET` operations (also known as HTTP _methods_).
+* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`.
+* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`.
+
+### Interactive API docs
+
+Now go to http://127.0.0.1:8000/docs.
+
+You will see the automatic interactive API documentation (provided by Swagger UI):
+
+
+
+### Alternative API docs
+
+And now, go to http://127.0.0.1:8000/redoc.
+
+You will see the alternative automatic documentation (provided by ReDoc):
+
+
+
+## Example upgrade
+
+Now modify the file `main.py` to receive a body from a `PUT` request.
+
+Declare the body using standard Python types, thanks to Pydantic.
+
+```Python hl_lines="4 9-12 25-27"
+from typing import Union
+
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ price: float
+ is_offer: Union[bool, None] = None
+
+
+@app.get("/")
+def read_root():
+ return {"Hello": "World"}
+
+
+@app.get("/items/{item_id}")
+def read_item(item_id: int, q: Union[str, None] = None):
+ return {"item_id": item_id, "q": q}
+
+
+@app.put("/items/{item_id}")
+def update_item(item_id: int, item: Item):
+ return {"item_name": item.name, "item_id": item_id}
+```
+
+The server should reload automatically (because you added `--reload` to the `uvicorn` command above).
+
+### Interactive API docs upgrade
+
+Now go to http://127.0.0.1:8000/docs.
+
+* The interactive API documentation will be automatically updated, including the new body:
+
+
+
+* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API:
+
+
+
+* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen:
+
+
+
+### Alternative API docs upgrade
+
+And now, go to http://127.0.0.1:8000/redoc.
+
+* The alternative documentation will also reflect the new query parameter and body:
+
+
+
+### Recap
+
+In summary, you declare **once** the types of parameters, body, etc. as function parameters.
+
+You do that with standard modern Python types.
+
+You don't have to learn a new syntax, the methods or classes of a specific library, etc.
+
+Just standard **Python 3.7+**.
+
+For example, for an `int`:
+
+```Python
+item_id: int
+```
+
+or for a more complex `Item` model:
+
+```Python
+item: Item
+```
+
+...and with that single declaration you get:
+
+* Editor support, including:
+ * Completion.
+ * Type checks.
+* Validation of data:
+ * Automatic and clear errors when the data is invalid.
+ * Validation even for deeply nested JSON objects.
+* Conversion of input data: coming from the network to Python data and types. Reading from:
+ * JSON.
+ * Path parameters.
+ * Query parameters.
+ * Cookies.
+ * Headers.
+ * Forms.
+ * Files.
+* Conversion of output data: converting from Python data and types to network data (as JSON):
+ * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc).
+ * `datetime` objects.
+ * `UUID` objects.
+ * Database models.
+ * ...and many more.
+* Automatic interactive API documentation, including 2 alternative user interfaces:
+ * Swagger UI.
+ * ReDoc.
+
+---
+
+Coming back to the previous code example, **FastAPI** will:
+
+* Validate that there is an `item_id` in the path for `GET` and `PUT` requests.
+* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests.
+ * If it is not, the client will see a useful, clear error.
+* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests.
+ * As the `q` parameter is declared with `= None`, it is optional.
+ * Without the `None` it would be required (as is the body in the case with `PUT`).
+* For `PUT` requests to `/items/{item_id}`, Read the body as JSON:
+ * Check that it has a required attribute `name` that should be a `str`.
+ * Check that it has a required attribute `price` that has to be a `float`.
+ * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present.
+ * All this would also work for deeply nested JSON objects.
+* Convert from and to JSON automatically.
+* Document everything with OpenAPI, that can be used by:
+ * Interactive documentation systems.
+ * Automatic client code generation systems, for many languages.
+* Provide 2 interactive documentation web interfaces directly.
+
+---
+
+We just scratched the surface, but you already get the idea of how it all works.
+
+Try changing the line with:
+
+```Python
+ return {"item_name": item.name, "item_id": item_id}
+```
+
+...from:
+
+```Python
+ ... "item_name": item.name ...
+```
+
+...to:
+
+```Python
+ ... "item_price": item.price ...
+```
+
+...and see how your editor will auto-complete the attributes and know their types:
+
+
+
+For a more complete example including more features, see the Tutorial - User Guide.
+
+**Spoiler alert**: the tutorial - user guide includes:
+
+* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**.
+* How to set **validation constraints** as `maximum_length` or `regex`.
+* A very powerful and easy to use **Dependency Injection** system.
+* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth.
+* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic).
+* **GraphQL** integration with Strawberry and other libraries.
+* Many extra features (thanks to Starlette) as:
+ * **WebSockets**
+ * extremely easy tests based on HTTPX and `pytest`
+ * **CORS**
+ * **Cookie Sessions**
+ * ...and more.
+
+## Performance
+
+Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as one of the fastest Python frameworks available, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
+
+To understand more about it, see the section Benchmarks.
+
+## Optional Dependencies
+
+Used by Pydantic:
+
+* ujson
- for faster JSON "parsing".
+* email_validator
- for email validation.
+
+Used by Starlette:
+
+* httpx
- Required if you want to use the `TestClient`.
+* jinja2
- Required if you want to use the default template configuration.
+* python-multipart
- Required if you want to support form "parsing", with `request.form()`.
+* itsdangerous
- Required for `SessionMiddleware` support.
+* pyyaml
- Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI).
+* ujson
- Required if you want to use `UJSONResponse`.
+
+Used by FastAPI / Starlette:
+
+* uvicorn
- for the server that loads and serves your application.
+* orjson
- Required if you want to use `ORJSONResponse`.
+
+You can install all of these with `pip install "fastapi[all]"`.
+
+## License
+
+This project is licensed under the terms of the MIT license.
diff --git a/docs/hy/mkdocs.yml b/docs/hy/mkdocs.yml
new file mode 100644
index 000000000..19d747c31
--- /dev/null
+++ b/docs/hy/mkdocs.yml
@@ -0,0 +1,160 @@
+site_name: FastAPI
+site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production
+site_url: https://fastapi.tiangolo.com/hy/
+theme:
+ name: material
+ custom_dir: overrides
+ palette:
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
+ primary: teal
+ accent: amber
+ toggle:
+ icon: material/lightbulb
+ name: Switch to light mode
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
+ primary: teal
+ accent: amber
+ toggle:
+ icon: material/lightbulb-outline
+ name: Switch to dark mode
+ features:
+ - search.suggest
+ - search.highlight
+ - content.tabs.link
+ icon:
+ repo: fontawesome/brands/github-alt
+ logo: https://fastapi.tiangolo.com/img/icon-white.svg
+ favicon: https://fastapi.tiangolo.com/img/favicon.png
+ language: hy
+repo_name: tiangolo/fastapi
+repo_url: https://github.com/tiangolo/fastapi
+edit_uri: ''
+plugins:
+- search
+- markdownextradata:
+ data: data
+nav:
+- FastAPI: index.md
+- Languages:
+ - en: /
+ - az: /az/
+ - cs: /cs/
+ - de: /de/
+ - em: /em/
+ - es: /es/
+ - fa: /fa/
+ - fr: /fr/
+ - he: /he/
+ - hy: /hy/
+ - id: /id/
+ - it: /it/
+ - ja: /ja/
+ - ko: /ko/
+ - lo: /lo/
+ - nl: /nl/
+ - pl: /pl/
+ - pt: /pt/
+ - ru: /ru/
+ - sq: /sq/
+ - sv: /sv/
+ - ta: /ta/
+ - tr: /tr/
+ - uk: /uk/
+ - zh: /zh/
+markdown_extensions:
+- toc:
+ permalink: true
+- markdown.extensions.codehilite:
+ guess_lang: false
+- mdx_include:
+ base_path: docs
+- admonition
+- codehilite
+- extra
+- pymdownx.superfences:
+ custom_fences:
+ - name: mermaid
+ class: mermaid
+ format: !!python/name:pymdownx.superfences.fence_code_format ''
+- pymdownx.tabbed:
+ alternate_style: true
+- attr_list
+- md_in_html
+extra:
+ analytics:
+ provider: google
+ property: G-YNEVN69SC3
+ social:
+ - icon: fontawesome/brands/github-alt
+ link: https://github.com/tiangolo/fastapi
+ - icon: fontawesome/brands/discord
+ link: https://discord.gg/VQjSZaeJmf
+ - icon: fontawesome/brands/twitter
+ link: https://twitter.com/fastapi
+ - icon: fontawesome/brands/linkedin
+ link: https://www.linkedin.com/in/tiangolo
+ - icon: fontawesome/brands/dev
+ link: https://dev.to/tiangolo
+ - icon: fontawesome/brands/medium
+ link: https://medium.com/@tiangolo
+ - icon: fontawesome/solid/globe
+ link: https://tiangolo.com
+ alternate:
+ - link: /
+ name: en - English
+ - link: /az/
+ name: az
+ - link: /cs/
+ name: cs
+ - link: /de/
+ name: de
+ - link: /em/
+ name: 😉
+ - link: /es/
+ name: es - español
+ - link: /fa/
+ name: fa
+ - link: /fr/
+ name: fr - français
+ - link: /he/
+ name: he
+ - link: /hy/
+ name: hy
+ - link: /id/
+ name: id
+ - link: /it/
+ name: it - italiano
+ - link: /ja/
+ name: ja - 日本語
+ - link: /ko/
+ name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
+ - link: /nl/
+ name: nl
+ - link: /pl/
+ name: pl
+ - link: /pt/
+ name: pt - português
+ - link: /ru/
+ name: ru - русский язык
+ - link: /sq/
+ name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
+ - link: /tr/
+ name: tr - Türkçe
+ - link: /uk/
+ name: uk - українська мова
+ - link: /zh/
+ name: zh - 汉语
+extra_css:
+- https://fastapi.tiangolo.com/css/termynal.css
+- https://fastapi.tiangolo.com/css/custom.css
+extra_javascript:
+- https://fastapi.tiangolo.com/js/termynal.js
+- https://fastapi.tiangolo.com/js/custom.js
diff --git a/docs/hy/overrides/.gitignore b/docs/hy/overrides/.gitignore
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs/id/mkdocs.yml b/docs/id/mkdocs.yml
index abb31252f..460cb6914 100644
--- a/docs/id/mkdocs.yml
+++ b/docs/id/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -80,7 +85,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -101,8 +106,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -111,6 +120,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -119,6 +130,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -131,6 +144,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/it/mkdocs.yml b/docs/it/mkdocs.yml
index 532b5bc52..b3a48482b 100644
--- a/docs/it/mkdocs.yml
+++ b/docs/it/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -80,7 +85,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -101,8 +106,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -111,6 +120,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -119,6 +130,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -131,6 +144,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/ja/docs/tutorial/testing.md b/docs/ja/docs/tutorial/testing.md
index 56f5cabac..037e9628f 100644
--- a/docs/ja/docs/tutorial/testing.md
+++ b/docs/ja/docs/tutorial/testing.md
@@ -74,16 +74,16 @@
これらの *path operation* には `X-Token` ヘッダーが必要です。
-=== "Python 3.6 and above"
+=== "Python 3.10+"
```Python
- {!> ../../../docs_src/app_testing/app_b/main.py!}
+ {!> ../../../docs_src/app_testing/app_b_py310/main.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
```Python
- {!> ../../../docs_src/app_testing/app_b_py310/main.py!}
+ {!> ../../../docs_src/app_testing/app_b/main.py!}
```
### 拡張版テストファイル
diff --git a/docs/ja/mkdocs.yml b/docs/ja/mkdocs.yml
index 5bbcce605..91b9a6658 100644
--- a/docs/ja/mkdocs.yml
+++ b/docs/ja/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -124,7 +129,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -145,8 +150,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -155,6 +164,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -163,6 +174,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -175,6 +188,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/ko/docs/tutorial/cors.md b/docs/ko/docs/tutorial/cors.md
new file mode 100644
index 000000000..39e9ea83f
--- /dev/null
+++ b/docs/ko/docs/tutorial/cors.md
@@ -0,0 +1,84 @@
+# 교차 출처 리소스 공유
+
+CORS 또는 "교차-출처 리소스 공유"란, 브라우저에서 동작하는 프론트엔드가 자바스크립트로 코드로 백엔드와 통신하고, 백엔드는 해당 프론트엔드와 다른 "출처"에 존재하는 상황을 의미합니다.
+
+## 출처
+
+출처란 프로토콜(`http` , `https`), 도메인(`myapp.com`, `localhost`, `localhost.tiangolo.com` ), 그리고 포트(`80`, `443`, `8080` )의 조합을 의미합니다.
+
+따라서, 아래는 모두 상이한 출처입니다:
+
+* `http://localhost`
+* `https://localhost`
+* `http://localhost:8080`
+
+모두 `localhost` 에 있지만, 서로 다른 프로토콜과 포트를 사용하고 있으므로 다른 "출처"입니다.
+
+## 단계
+
+브라우저 내 `http://localhost:8080`에서 동작하는 프론트엔드가 있고, 자바스크립트는 `http://localhost`를 통해 백엔드와 통신한다고 가정해봅시다(포트를 명시하지 않는 경우, 브라우저는 `80` 을 기본 포트로 간주합니다).
+
+그러면 브라우저는 백엔드에 HTTP `OPTIONS` 요청을 보내고, 백엔드에서 이 다른 출처(`http://localhost:8080`)와의 통신을 허가하는 적절한 헤더를 보내면, 브라우저는 프론트엔드의 자바스크립트가 백엔드에 요청을 보낼 수 있도록 합니다.
+
+이를 위해, 백엔드는 "허용된 출처(allowed origins)" 목록을 가지고 있어야만 합니다.
+
+이 경우, 프론트엔드가 제대로 동작하기 위해 `http://localhost:8080`을 목록에 포함해야 합니다.
+
+## 와일드카드
+
+모든 출처를 허용하기 위해 목록을 `"*"` ("와일드카드")로 선언하는 것도 가능합니다.
+
+하지만 이것은 특정한 유형의 통신만을 허용하며, 쿠키 및 액세스 토큰과 사용되는 인증 헤더(Authoriztion header) 등이 포함된 경우와 같이 자격 증명(credentials)이 포함된 통신은 허용되지 않습니다.
+
+따라서 모든 작업을 의도한대로 실행하기 위해, 허용되는 출처를 명시적으로 지정하는 것이 좋습니다.
+
+## `CORSMiddleware` 사용
+
+`CORSMiddleware` 을 사용하여 **FastAPI** 응용 프로그램의 교차 출처 리소스 공유 환경을 설정할 수 있습니다.
+
+* `CORSMiddleware` 임포트.
+* 허용되는 출처(문자열 형식)의 리스트 생성.
+* FastAPI 응용 프로그램에 "미들웨어(middleware)"로 추가.
+
+백엔드에서 다음의 사항을 허용할지에 대해 설정할 수도 있습니다:
+
+* 자격증명 (인증 헤더, 쿠키 등).
+* 특정한 HTTP 메소드(`POST`, `PUT`) 또는 와일드카드 `"*"` 를 사용한 모든 HTTP 메소드.
+* 특정한 HTTP 헤더 또는 와일드카드 `"*"` 를 사용한 모든 HTTP 헤더.
+
+```Python hl_lines="2 6-11 13-19"
+{!../../../docs_src/cors/tutorial001.py!}
+```
+
+`CORSMiddleware` 에서 사용하는 기본 매개변수는 제한적이므로, 브라우저가 교차-도메인 상황에서 특정한 출처, 메소드, 헤더 등을 사용할 수 있도록 하려면 이들을 명시적으로 허용해야 합니다.
+
+다음의 인자들이 지원됩니다:
+
+* `allow_origins` - 교차-출처 요청을 보낼 수 있는 출처의 리스트입니다. 예) `['https://example.org', 'https://www.example.org']`. 모든 출처를 허용하기 위해 `['*']` 를 사용할 수 있습니다.
+* `allow_origin_regex` - 교차-출처 요청을 보낼 수 있는 출처를 정규표현식 문자열로 나타냅니다. `'https://.*\.example\.org'`.
+* `allow_methods` - 교차-출처 요청을 허용하는 HTTP 메소드의 리스트입니다. 기본값은 `['GET']` 입니다. `['*']` 을 사용하여 모든 표준 메소드들을 허용할 수 있습니다.
+* `allow_headers` - 교차-출처를 지원하는 HTTP 요청 헤더의 리스트입니다. 기본값은 `[]` 입니다. 모든 헤더들을 허용하기 위해 `['*']` 를 사용할 수 있습니다. `Accept`, `Accept-Language`, `Content-Language` 그리고 `Content-Type` 헤더는 CORS 요청시 언제나 허용됩니다.
+* `allow_credentials` - 교차-출처 요청시 쿠키 지원 여부를 설정합니다. 기본값은 `False` 입니다. 또한 해당 항목을 허용할 경우 `allow_origins` 는 `['*']` 로 설정할 수 없으며, 출처를 반드시 특정해야 합니다.
+* `expose_headers` - 브라우저에 접근할 수 있어야 하는 모든 응답 헤더를 가리킵니다. 기본값은 `[]` 입니다.
+* `max_age` - 브라우저가 CORS 응답을 캐시에 저장하는 최대 시간을 초 단위로 설정합니다. 기본값은 `600` 입니다.
+
+미들웨어는 두가지 특정한 종류의 HTTP 요청에 응답합니다...
+
+### CORS 사전 요청
+
+`Origin` 및 `Access-Control-Request-Method` 헤더와 함께 전송하는 모든 `OPTIONS` 요청입니다.
+
+이 경우 미들웨어는 들어오는 요청을 가로채 적절한 CORS 헤더와, 정보 제공을 위한 `200` 또는 `400` 응답으로 응답합니다.
+
+### 단순한 요청
+
+`Origin` 헤더를 가진 모든 요청. 이 경우 미들웨어는 요청을 정상적으로 전달하지만, 적절한 CORS 헤더를 응답에 포함시킵니다.
+
+## 더 많은 정보
+
+CORS에 대한 더 많은 정보를 알고싶다면, Mozilla CORS 문서를 참고하기 바랍니다.
+
+!!! note "기술적 세부 사항"
+ `from starlette.middleware.cors import CORSMiddleware` 역시 사용할 수 있습니다.
+
+ **FastAPI**는 개발자인 당신의 편의를 위해 `fastapi.middleware` 에서 몇가지의 미들웨어를 제공합니다. 하지만 대부분의 미들웨어가 Stralette으로부터 직접 제공됩니다.
diff --git a/docs/ko/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/ko/docs/tutorial/dependencies/classes-as-dependencies.md
new file mode 100644
index 000000000..bbf3a8283
--- /dev/null
+++ b/docs/ko/docs/tutorial/dependencies/classes-as-dependencies.md
@@ -0,0 +1,244 @@
+# 의존성으로서의 클래스
+
+**의존성 주입** 시스템에 대해 자세히 살펴보기 전에 이전 예제를 업그레이드 해보겠습니다.
+
+## 이전 예제의 `딕셔너리`
+
+이전 예제에서, 우리는 의존성(의존 가능한) 함수에서 `딕셔너리`객체를 반환하고 있었습니다:
+
+=== "파이썬 3.6 이상"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/dependencies/tutorial001.py!}
+ ```
+
+=== "파이썬 3.10 이상"
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/dependencies/tutorial001_py310.py!}
+ ```
+
+우리는 *경로 작동 함수*의 매개변수 `commons`에서 `딕셔너리` 객체를 얻습니다.
+
+그리고 우리는 에디터들이 `딕셔너리` 객체의 키나 밸류의 자료형을 알 수 없기 때문에 자동 완성과 같은 기능을 제공해 줄 수 없다는 것을 알고 있습니다.
+
+더 나은 방법이 있을 것 같습니다...
+
+## 의존성으로 사용 가능한 것
+
+지금까지 함수로 선언된 의존성을 봐왔습니다.
+
+아마도 더 일반적이기는 하겠지만 의존성을 선언하는 유일한 방법은 아닙니다.
+
+핵심 요소는 의존성이 "호출 가능"해야 한다는 것입니다
+
+파이썬에서의 "**호출 가능**"은 파이썬이 함수처럼 "호출"할 수 있는 모든 것입니다.
+
+따라서, 만약 당신이 `something`(함수가 아닐 수도 있음) 객체를 가지고 있고,
+
+```Python
+something()
+```
+
+또는
+
+```Python
+something(some_argument, some_keyword_argument="foo")
+```
+
+상기와 같은 방식으로 "호출(실행)" 할 수 있다면 "호출 가능"이 됩니다.
+
+## 의존성으로서의 클래스
+
+파이썬 클래스의 인스턴스를 생성하기 위해 사용하는 것과 동일한 문법을 사용한다는 걸 알 수 있습니다.
+
+예를 들어:
+
+```Python
+class Cat:
+ def __init__(self, name: str):
+ self.name = name
+
+
+fluffy = Cat(name="Mr Fluffy")
+```
+
+이 경우에 `fluffy`는 클래스 `Cat`의 인스턴스입니다. 그리고 우리는 `fluffy`를 만들기 위해서 `Cat`을 "호출"했습니다.
+
+따라서, 파이썬 클래스는 **호출 가능**합니다.
+
+그래서 **FastAPI**에서는 파이썬 클래스를 의존성으로 사용할 수 있습니다.
+
+FastAPI가 실질적으로 확인하는 것은 "호출 가능성"(함수, 클래스 또는 다른 모든 것)과 정의된 매개변수들입니다.
+
+"호출 가능"한 것을 의존성으로서 **FastAPI**에 전달하면, 그 "호출 가능"한 것의 매개변수들을 분석한 후 이를 *경로 동작 함수*를 위한 매개변수와 동일한 방식으로 처리합니다. 하위-의존성 또한 같은 방식으로 처리합니다.
+
+매개변수가 없는 "호출 가능"한 것 역시 매개변수가 없는 *경로 동작 함수*와 동일한 방식으로 적용됩니다.
+
+그래서, 우리는 위 예제에서의 `common_paramenters` 의존성을 클래스 `CommonQueryParams`로 바꿀 수 있습니다.
+
+=== "파이썬 3.6 이상"
+
+ ```Python hl_lines="11-15"
+ {!> ../../../docs_src/dependencies/tutorial002.py!}
+ ```
+
+=== "파이썬 3.10 이상"
+
+ ```Python hl_lines="9-13"
+ {!> ../../../docs_src/dependencies/tutorial002_py310.py!}
+ ```
+
+클래스의 인스턴스를 생성하는 데 사용되는 `__init__` 메서드에 주목하기 바랍니다:
+
+=== "파이썬 3.6 이상"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/dependencies/tutorial002.py!}
+ ```
+
+=== "파이썬 3.10 이상"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/dependencies/tutorial002_py310.py!}
+ ```
+
+...이전 `common_parameters`와 동일한 매개변수를 가집니다:
+
+=== "파이썬 3.6 이상"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/dependencies/tutorial001.py!}
+ ```
+
+=== "파이썬 3.10 이상"
+
+ ```Python hl_lines="6"
+ {!> ../../../docs_src/dependencies/tutorial001_py310.py!}
+ ```
+
+이 매개변수들은 **FastAPI**가 의존성을 "해결"하기 위해 사용할 것입니다
+
+함수와 클래스 두 가지 방식 모두, 아래 요소를 갖습니다:
+
+* `문자열`이면서 선택사항인 쿼리 매개변수 `q`.
+* 기본값이 `0`이면서 `정수형`인 쿼리 매개변수 `skip`
+* 기본값이 `100`이면서 `정수형`인 쿼리 매개변수 `limit`
+
+두 가지 방식 모두, 데이터는 변환, 검증되고 OpenAPI 스키마에 문서화됩니다.
+
+## 사용해봅시다!
+
+이제 아래의 클래스를 이용해서 의존성을 정의할 수 있습니다.
+
+=== "파이썬 3.6 이상"
+
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/dependencies/tutorial002.py!}
+ ```
+
+=== "파이썬 3.10 이상"
+
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/dependencies/tutorial002_py310.py!}
+ ```
+
+**FastAPI**는 `CommonQueryParams` 클래스를 호출합니다. 이것은 해당 클래스의 "인스턴스"를 생성하고 그 인스턴스는 함수의 매개변수 `commons`로 전달됩니다.
+
+## 타입 힌팅 vs `Depends`
+
+위 코드에서 `CommonQueryParams`를 두 번 작성한 방식에 주목하십시오:
+
+```Python
+commons: CommonQueryParams = Depends(CommonQueryParams)
+```
+
+마지막 `CommonQueryParams` 변수를 보면:
+
+```Python
+... = Depends(CommonQueryParams)
+```
+
+... **FastAPI**가 실제로 어떤 것이 의존성인지 알기 위해서 사용하는 방법입니다.
+FastAPI는 선언된 매개변수들을 추출할 것이고 실제로 이 변수들을 호출할 것입니다.
+
+---
+
+이 경우에, 첫번째 `CommonQueryParams` 변수를 보면:
+
+```Python
+commons: CommonQueryParams ...
+```
+
+... **FastAPI**는 `CommonQueryParams` 변수에 어떠한 특별한 의미도 부여하지 않습니다. FastAPI는 이 변수를 데이터 변환, 검증 등에 활용하지 않습니다. (활용하려면 `= Depends(CommonQueryParams)`를 사용해야 합니다.)
+
+사실 아래와 같이 작성해도 무관합니다:
+
+```Python
+commons = Depends(CommonQueryParams)
+```
+
+..전체적인 코드는 아래와 같습니다:
+
+=== "파이썬 3.6 이상"
+
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/dependencies/tutorial003.py!}
+ ```
+
+=== "파이썬 3.10 이상"
+
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/dependencies/tutorial003_py310.py!}
+ ```
+
+그러나 자료형을 선언하면 에디터가 매개변수 `commons`로 전달될 것이 무엇인지 알게 되고, 이를 통해 코드 완성, 자료형 확인 등에 도움이 될 수 있으므로 권장됩니다.
+
+
+
+## 코드 단축
+
+그러나 여기 `CommonQueryParams`를 두 번이나 작성하는, 코드 반복이 있다는 것을 알 수 있습니다:
+
+```Python
+commons: CommonQueryParams = Depends(CommonQueryParams)
+```
+
+**FastAPI**는 *특히* 의존성이 **FastAPI**가 클래스 자체의 인스턴스를 생성하기 위해 "호출"하는 클래스인 경우, 조금 더 쉬운 방법을 제공합니다.
+
+이러한 특정한 경우에는 아래처럼 사용할 수 있습니다:
+
+이렇게 쓰는 것 대신:
+
+```Python
+commons: CommonQueryParams = Depends(CommonQueryParams)
+```
+
+...이렇게 쓸 수 있습니다.:
+
+```Python
+commons: CommonQueryParams = Depends()
+```
+
+의존성을 매개변수의 타입으로 선언하는 경우 `Depends(CommonQueryParams)`처럼 클래스 이름 전체를 *다시* 작성하는 대신, 매개변수를 넣지 않은 `Depends()`의 형태로 사용할 수 있습니다.
+
+아래에 같은 예제가 있습니다:
+
+=== "파이썬 3.6 이상"
+
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/dependencies/tutorial004.py!}
+ ```
+
+=== "파이썬 3.10 이상"
+
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/dependencies/tutorial004_py310.py!}
+ ```
+
+...이렇게 코드를 단축하여도 **FastAPI**는 무엇을 해야하는지 알고 있습니다.
+
+!!! tip "팁"
+ 만약 이것이 도움이 되기보다 더 헷갈리게 만든다면, 잊어버리십시오. 이것이 반드시 필요한 것은 아닙니다.
+
+ 이것은 단지 손쉬운 방법일 뿐입니다. 왜냐하면 **FastAPI**는 코드 반복을 최소화할 수 있는 방법을 고민하기 때문입니다.
diff --git a/docs/ko/mkdocs.yml b/docs/ko/mkdocs.yml
index 50931e134..aec1c7569 100644
--- a/docs/ko/mkdocs.yml
+++ b/docs/ko/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -69,6 +74,9 @@ nav:
- tutorial/request-files.md
- tutorial/request-forms-and-files.md
- tutorial/encoder.md
+ - tutorial/cors.md
+ - 의존성:
+ - tutorial/dependencies/classes-as-dependencies.md
markdown_extensions:
- toc:
permalink: true
@@ -91,7 +99,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -112,8 +120,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -122,6 +134,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -130,6 +144,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -142,6 +158,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/lo/docs/index.md b/docs/lo/docs/index.md
new file mode 100644
index 000000000..9a81f14d1
--- /dev/null
+++ b/docs/lo/docs/index.md
@@ -0,0 +1,469 @@
+
+
+
+
+ FastAPI framework, high performance, easy to learn, fast to code, ready for production
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+**Documentation**: https://fastapi.tiangolo.com
+
+**Source Code**: https://github.com/tiangolo/fastapi
+
+---
+
+FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints.
+
+The key features are:
+
+* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance).
+* **Fast to code**: Increase the speed to develop features by about 200% to 300%. *
+* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. *
+* **Intuitive**: Great editor support. Completion everywhere. Less time debugging.
+* **Easy**: Designed to be easy to use and learn. Less time reading docs.
+* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
+* **Robust**: Get production-ready code. With automatic interactive documentation.
+* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema.
+
+* estimation based on tests on an internal development team, building production applications.
+
+## Sponsors
+
+
+
+{% if sponsors %}
+{% for sponsor in sponsors.gold -%}
+
+{% endfor -%}
+{%- for sponsor in sponsors.silver -%}
+
+{% endfor %}
+{% endif %}
+
+
+
+Other sponsors
+
+## Opinions
+
+"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._"
+
+Kabir Khan -
Microsoft (ref)
+
+---
+
+"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_"
+
+Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala -
Uber (ref)
+
+---
+
+"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_"
+
+Kevin Glisson, Marc Vilanova, Forest Monsen -
Netflix (ref)
+
+---
+
+"_I’m over the moon excited about **FastAPI**. It’s so fun!_"
+
+
+
+---
+
+"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._"
+
+
+
+---
+
+"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_"
+
+"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_"
+
+
+
+---
+
+"_If anyone is looking to build a production Python API, I would highly recommend **FastAPI**. It is **beautifully designed**, **simple to use** and **highly scalable**, it has become a **key component** in our API first development strategy and is driving many automations and services such as our Virtual TAC Engineer._"
+
+Deon Pillsbury -
Cisco (ref)
+
+---
+
+## **Typer**, the FastAPI of CLIs
+
+
+
+If you are building a CLI app to be used in the terminal instead of a web API, check out **Typer**.
+
+**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀
+
+## Requirements
+
+Python 3.7+
+
+FastAPI stands on the shoulders of giants:
+
+* Starlette for the web parts.
+* Pydantic for the data parts.
+
+## Installation
+
+
+
+```console
+$ pip install fastapi
+
+---> 100%
+```
+
+
+
+You will also need an ASGI server, for production such as Uvicorn or Hypercorn.
+
+
+
+```console
+$ pip install "uvicorn[standard]"
+
+---> 100%
+```
+
+
+
+## Example
+
+### Create it
+
+* Create a file `main.py` with:
+
+```Python
+from typing import Union
+
+from fastapi import FastAPI
+
+app = FastAPI()
+
+
+@app.get("/")
+def read_root():
+ return {"Hello": "World"}
+
+
+@app.get("/items/{item_id}")
+def read_item(item_id: int, q: Union[str, None] = None):
+ return {"item_id": item_id, "q": q}
+```
+
+
+Or use async def
...
+
+If your code uses `async` / `await`, use `async def`:
+
+```Python hl_lines="9 14"
+from typing import Union
+
+from fastapi import FastAPI
+
+app = FastAPI()
+
+
+@app.get("/")
+async def read_root():
+ return {"Hello": "World"}
+
+
+@app.get("/items/{item_id}")
+async def read_item(item_id: int, q: Union[str, None] = None):
+ return {"item_id": item_id, "q": q}
+```
+
+**Note**:
+
+If you don't know, check the _"In a hurry?"_ section about `async` and `await` in the docs.
+
+
+
+### Run it
+
+Run the server with:
+
+
+
+```console
+$ uvicorn main:app --reload
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+INFO: Started reloader process [28720]
+INFO: Started server process [28722]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+```
+
+
+
+
+About the command uvicorn main:app --reload
...
+
+The command `uvicorn main:app` refers to:
+
+* `main`: the file `main.py` (the Python "module").
+* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.
+* `--reload`: make the server restart after code changes. Only do this for development.
+
+
+
+### Check it
+
+Open your browser at http://127.0.0.1:8000/items/5?q=somequery.
+
+You will see the JSON response as:
+
+```JSON
+{"item_id": 5, "q": "somequery"}
+```
+
+You already created an API that:
+
+* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`.
+* Both _paths_ take `GET` operations (also known as HTTP _methods_).
+* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`.
+* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`.
+
+### Interactive API docs
+
+Now go to http://127.0.0.1:8000/docs.
+
+You will see the automatic interactive API documentation (provided by Swagger UI):
+
+
+
+### Alternative API docs
+
+And now, go to http://127.0.0.1:8000/redoc.
+
+You will see the alternative automatic documentation (provided by ReDoc):
+
+
+
+## Example upgrade
+
+Now modify the file `main.py` to receive a body from a `PUT` request.
+
+Declare the body using standard Python types, thanks to Pydantic.
+
+```Python hl_lines="4 9-12 25-27"
+from typing import Union
+
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ price: float
+ is_offer: Union[bool, None] = None
+
+
+@app.get("/")
+def read_root():
+ return {"Hello": "World"}
+
+
+@app.get("/items/{item_id}")
+def read_item(item_id: int, q: Union[str, None] = None):
+ return {"item_id": item_id, "q": q}
+
+
+@app.put("/items/{item_id}")
+def update_item(item_id: int, item: Item):
+ return {"item_name": item.name, "item_id": item_id}
+```
+
+The server should reload automatically (because you added `--reload` to the `uvicorn` command above).
+
+### Interactive API docs upgrade
+
+Now go to http://127.0.0.1:8000/docs.
+
+* The interactive API documentation will be automatically updated, including the new body:
+
+
+
+* Click on the button "Try it out", it allows you to fill the parameters and directly interact with the API:
+
+
+
+* Then click on the "Execute" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen:
+
+
+
+### Alternative API docs upgrade
+
+And now, go to http://127.0.0.1:8000/redoc.
+
+* The alternative documentation will also reflect the new query parameter and body:
+
+
+
+### Recap
+
+In summary, you declare **once** the types of parameters, body, etc. as function parameters.
+
+You do that with standard modern Python types.
+
+You don't have to learn a new syntax, the methods or classes of a specific library, etc.
+
+Just standard **Python 3.7+**.
+
+For example, for an `int`:
+
+```Python
+item_id: int
+```
+
+or for a more complex `Item` model:
+
+```Python
+item: Item
+```
+
+...and with that single declaration you get:
+
+* Editor support, including:
+ * Completion.
+ * Type checks.
+* Validation of data:
+ * Automatic and clear errors when the data is invalid.
+ * Validation even for deeply nested JSON objects.
+* Conversion of input data: coming from the network to Python data and types. Reading from:
+ * JSON.
+ * Path parameters.
+ * Query parameters.
+ * Cookies.
+ * Headers.
+ * Forms.
+ * Files.
+* Conversion of output data: converting from Python data and types to network data (as JSON):
+ * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc).
+ * `datetime` objects.
+ * `UUID` objects.
+ * Database models.
+ * ...and many more.
+* Automatic interactive API documentation, including 2 alternative user interfaces:
+ * Swagger UI.
+ * ReDoc.
+
+---
+
+Coming back to the previous code example, **FastAPI** will:
+
+* Validate that there is an `item_id` in the path for `GET` and `PUT` requests.
+* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests.
+ * If it is not, the client will see a useful, clear error.
+* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests.
+ * As the `q` parameter is declared with `= None`, it is optional.
+ * Without the `None` it would be required (as is the body in the case with `PUT`).
+* For `PUT` requests to `/items/{item_id}`, Read the body as JSON:
+ * Check that it has a required attribute `name` that should be a `str`.
+ * Check that it has a required attribute `price` that has to be a `float`.
+ * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present.
+ * All this would also work for deeply nested JSON objects.
+* Convert from and to JSON automatically.
+* Document everything with OpenAPI, that can be used by:
+ * Interactive documentation systems.
+ * Automatic client code generation systems, for many languages.
+* Provide 2 interactive documentation web interfaces directly.
+
+---
+
+We just scratched the surface, but you already get the idea of how it all works.
+
+Try changing the line with:
+
+```Python
+ return {"item_name": item.name, "item_id": item_id}
+```
+
+...from:
+
+```Python
+ ... "item_name": item.name ...
+```
+
+...to:
+
+```Python
+ ... "item_price": item.price ...
+```
+
+...and see how your editor will auto-complete the attributes and know their types:
+
+
+
+For a more complete example including more features, see the Tutorial - User Guide.
+
+**Spoiler alert**: the tutorial - user guide includes:
+
+* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**.
+* How to set **validation constraints** as `maximum_length` or `regex`.
+* A very powerful and easy to use **Dependency Injection** system.
+* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth.
+* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic).
+* **GraphQL** integration with Strawberry and other libraries.
+* Many extra features (thanks to Starlette) as:
+ * **WebSockets**
+ * extremely easy tests based on HTTPX and `pytest`
+ * **CORS**
+ * **Cookie Sessions**
+ * ...and more.
+
+## Performance
+
+Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as one of the fastest Python frameworks available, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
+
+To understand more about it, see the section Benchmarks.
+
+## Optional Dependencies
+
+Used by Pydantic:
+
+* ujson
- for faster JSON "parsing".
+* email_validator
- for email validation.
+
+Used by Starlette:
+
+* httpx
- Required if you want to use the `TestClient`.
+* jinja2
- Required if you want to use the default template configuration.
+* python-multipart
- Required if you want to support form "parsing", with `request.form()`.
+* itsdangerous
- Required for `SessionMiddleware` support.
+* pyyaml
- Required for Starlette's `SchemaGenerator` support (you probably don't need it with FastAPI).
+* ujson
- Required if you want to use `UJSONResponse`.
+
+Used by FastAPI / Starlette:
+
+* uvicorn
- for the server that loads and serves your application.
+* orjson
- Required if you want to use `ORJSONResponse`.
+
+You can install all of these with `pip install "fastapi[all]"`.
+
+## License
+
+This project is licensed under the terms of the MIT license.
diff --git a/docs/lo/mkdocs.yml b/docs/lo/mkdocs.yml
new file mode 100644
index 000000000..450ebcd2b
--- /dev/null
+++ b/docs/lo/mkdocs.yml
@@ -0,0 +1,157 @@
+site_name: FastAPI
+site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production
+site_url: https://fastapi.tiangolo.com/lo/
+theme:
+ name: material
+ custom_dir: overrides
+ palette:
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
+ primary: teal
+ accent: amber
+ toggle:
+ icon: material/lightbulb
+ name: Switch to light mode
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
+ primary: teal
+ accent: amber
+ toggle:
+ icon: material/lightbulb-outline
+ name: Switch to dark mode
+ features:
+ - search.suggest
+ - search.highlight
+ - content.tabs.link
+ icon:
+ repo: fontawesome/brands/github-alt
+ logo: https://fastapi.tiangolo.com/img/icon-white.svg
+ favicon: https://fastapi.tiangolo.com/img/favicon.png
+ language: en
+repo_name: tiangolo/fastapi
+repo_url: https://github.com/tiangolo/fastapi
+edit_uri: ''
+plugins:
+- search
+- markdownextradata:
+ data: data
+nav:
+- FastAPI: index.md
+- Languages:
+ - en: /
+ - az: /az/
+ - de: /de/
+ - em: /em/
+ - es: /es/
+ - fa: /fa/
+ - fr: /fr/
+ - he: /he/
+ - hy: /hy/
+ - id: /id/
+ - it: /it/
+ - ja: /ja/
+ - ko: /ko/
+ - lo: /lo/
+ - nl: /nl/
+ - pl: /pl/
+ - pt: /pt/
+ - ru: /ru/
+ - sq: /sq/
+ - sv: /sv/
+ - ta: /ta/
+ - tr: /tr/
+ - uk: /uk/
+ - zh: /zh/
+markdown_extensions:
+- toc:
+ permalink: true
+- markdown.extensions.codehilite:
+ guess_lang: false
+- mdx_include:
+ base_path: docs
+- admonition
+- codehilite
+- extra
+- pymdownx.superfences:
+ custom_fences:
+ - name: mermaid
+ class: mermaid
+ format: !!python/name:pymdownx.superfences.fence_code_format ''
+- pymdownx.tabbed:
+ alternate_style: true
+- attr_list
+- md_in_html
+extra:
+ analytics:
+ provider: google
+ property: G-YNEVN69SC3
+ social:
+ - icon: fontawesome/brands/github-alt
+ link: https://github.com/tiangolo/fastapi
+ - icon: fontawesome/brands/discord
+ link: https://discord.gg/VQjSZaeJmf
+ - icon: fontawesome/brands/twitter
+ link: https://twitter.com/fastapi
+ - icon: fontawesome/brands/linkedin
+ link: https://www.linkedin.com/in/tiangolo
+ - icon: fontawesome/brands/dev
+ link: https://dev.to/tiangolo
+ - icon: fontawesome/brands/medium
+ link: https://medium.com/@tiangolo
+ - icon: fontawesome/solid/globe
+ link: https://tiangolo.com
+ alternate:
+ - link: /
+ name: en - English
+ - link: /az/
+ name: az
+ - link: /de/
+ name: de
+ - link: /em/
+ name: 😉
+ - link: /es/
+ name: es - español
+ - link: /fa/
+ name: fa
+ - link: /fr/
+ name: fr - français
+ - link: /he/
+ name: he
+ - link: /hy/
+ name: hy
+ - link: /id/
+ name: id
+ - link: /it/
+ name: it - italiano
+ - link: /ja/
+ name: ja - 日本語
+ - link: /ko/
+ name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
+ - link: /nl/
+ name: nl
+ - link: /pl/
+ name: pl
+ - link: /pt/
+ name: pt - português
+ - link: /ru/
+ name: ru - русский язык
+ - link: /sq/
+ name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
+ - link: /tr/
+ name: tr - Türkçe
+ - link: /uk/
+ name: uk - українська мова
+ - link: /zh/
+ name: zh - 汉语
+extra_css:
+- https://fastapi.tiangolo.com/css/termynal.css
+- https://fastapi.tiangolo.com/css/custom.css
+extra_javascript:
+- https://fastapi.tiangolo.com/js/termynal.js
+- https://fastapi.tiangolo.com/js/custom.js
diff --git a/docs/lo/overrides/.gitignore b/docs/lo/overrides/.gitignore
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs/nl/mkdocs.yml b/docs/nl/mkdocs.yml
index 6d46939f9..96c93abff 100644
--- a/docs/nl/mkdocs.yml
+++ b/docs/nl/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -80,7 +85,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -101,8 +106,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -111,6 +120,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -119,6 +130,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -131,6 +144,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/pl/mkdocs.yml b/docs/pl/mkdocs.yml
index 1cd129420..0d7a783fc 100644
--- a/docs/pl/mkdocs.yml
+++ b/docs/pl/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -83,7 +88,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -104,8 +109,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -114,6 +123,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -122,6 +133,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -134,6 +147,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/pt/docs/advanced/events.md b/docs/pt/docs/advanced/events.md
new file mode 100644
index 000000000..7f6cb6f5d
--- /dev/null
+++ b/docs/pt/docs/advanced/events.md
@@ -0,0 +1,163 @@
+# Eventos de vida útil
+
+Você pode definir a lógica (código) que poderia ser executada antes da aplicação **inicializar**. Isso significa que esse código será executado **uma vez**, **antes** da aplicação **começar a receber requisições**.
+
+Do mesmo modo, você pode definir a lógica (código) que será executada quando a aplicação estiver sendo **encerrada**. Nesse caso, este código será executado **uma vez**, **depois** de ter possivelmente tratado **várias requisições**.
+
+Por conta desse código ser executado antes da aplicação **começar** a receber requisições, e logo após **terminar** de lidar com as requisições, ele cobre toda a **vida útil** (_lifespan_) da aplicação (o termo "vida útil" será importante em um segundo 😉).
+
+Pode ser muito útil para configurar **recursos** que você precisa usar por toda aplicação, e que são **compartilhados** entre as requisições, e/ou que você precisa **limpar** depois. Por exemplo, o pool de uma conexão com o banco de dados ou carregamento de um modelo compartilhado de aprendizado de máquina (_machine learning_).
+
+## Caso de uso
+
+Vamos iniciar com um exemplo de **caso de uso** e então ver como resolvê-lo com isso.
+
+Vamos imaginar que você tem alguns **modelos de _machine learning_** que deseja usar para lidar com as requisições. 🤖
+
+Os mesmos modelos são compartilhados entre as requisições, então não é um modelo por requisição, ou um por usuário ou algo parecido.
+
+Vamos imaginar que o carregamento do modelo pode **demorar bastante tempo**, porque ele tem que ler muitos **dados do disco**. Então você não quer fazer isso a cada requisição.
+
+Você poderia carregá-lo no nível mais alto do módulo/arquivo, mas isso também poderia significaria **carregar o modelo** mesmo se você estiver executando um simples teste automatizado, então esse teste poderia ser **lento** porque teria que esperar o carregamento do modelo antes de ser capaz de executar uma parte independente do código.
+
+
+Isso é que nós iremos resolver, vamos carregar o modelo antes das requisições serem manuseadas, mas apenas um pouco antes da aplicação começar a receber requisições, não enquanto o código estiver sendo carregado.
+
+## Vida útil (_Lifespan_)
+
+Você pode definir essa lógica de *inicialização* e *encerramento* usando os parâmetros de `lifespan` da aplicação `FastAPI`, e um "gerenciador de contexto" (te mostrarei o que é isso a seguir).
+
+Vamos iniciar com um exemplo e ver isso detalhadamente.
+
+Nós criamos uma função assíncrona chamada `lifespan()` com `yield` como este:
+
+```Python hl_lines="16 19"
+{!../../../docs_src/events/tutorial003.py!}
+```
+
+Aqui nós estamos simulando a *inicialização* custosa do carregamento do modelo colocando a (falsa) função de modelo no dicionário com modelos de _machine learning_ antes do `yield`. Este código será executado **antes** da aplicação **começar a receber requisições**, durante a *inicialização*.
+
+E então, logo após o `yield`, descarregaremos o modelo. Esse código será executado **após** a aplicação **terminar de lidar com as requisições**, pouco antes do *encerramento*. Isso poderia, por exemplo, liberar recursos como memória ou GPU.
+
+!!! tip "Dica"
+ O `shutdown` aconteceria quando você estivesse **encerrando** a aplicação.
+
+ Talvez você precise inicializar uma nova versão, ou apenas cansou de executá-la. 🤷
+
+### Função _lifespan_
+
+A primeira coisa a notar, é que estamos definindo uma função assíncrona com `yield`. Isso é muito semelhante à Dependências com `yield`.
+
+```Python hl_lines="14-19"
+{!../../../docs_src/events/tutorial003.py!}
+```
+
+A primeira parte da função, antes do `yield`, será executada **antes** da aplicação inicializar.
+
+E a parte posterior do `yield` irá executar **após** a aplicação ser encerrada.
+
+### Gerenciador de Contexto Assíncrono
+
+Se você verificar, a função está decorada com um `@asynccontextmanager`.
+
+Que converte a função em algo chamado de "**Gerenciador de Contexto Assíncrono**".
+
+```Python hl_lines="1 13"
+{!../../../docs_src/events/tutorial003.py!}
+```
+
+Um **gerenciador de contexto** em Python é algo que você pode usar em uma declaração `with`, por exemplo, `open()` pode ser usado como um gerenciador de contexto:
+
+```Python
+with open("file.txt") as file:
+ file.read()
+```
+
+Nas versões mais recentes de Python, há também um **gerenciador de contexto assíncrono**. Você o usaria com `async with`:
+
+```Python
+async with lifespan(app):
+ await do_stuff()
+```
+
+Quando você cria um gerenciador de contexto ou um gerenciador de contexto assíncrono como mencionado acima, o que ele faz é que, antes de entrar no bloco `with`, ele irá executar o código anterior ao `yield`, e depois de sair do bloco `with`, ele irá executar o código depois do `yield`.
+
+No nosso exemplo de código acima, nós não usamos ele diretamente, mas nós passamos para o FastAPI para ele usá-lo.
+
+O parâmetro `lifespan` da aplicação `FastAPI` usa um **Gerenciador de Contexto Assíncrono**, então nós podemos passar nosso novo gerenciador de contexto assíncrono do `lifespan` para ele.
+
+```Python hl_lines="22"
+{!../../../docs_src/events/tutorial003.py!}
+```
+
+## Eventos alternativos (deprecados)
+
+!!! warning "Aviso"
+ A maneira recomendada para lidar com a *inicialização* e o *encerramento* é usando o parâmetro `lifespan` da aplicação `FastAPI` como descrito acima.
+
+ Você provavelmente pode pular essa parte.
+
+Existe uma forma alternativa para definir a execução dessa lógica durante *inicialização* e durante *encerramento*.
+
+Você pode definir manipuladores de eventos (funções) que precisam ser executadas antes da aplicação inicializar, ou quando a aplicação estiver encerrando.
+
+Essas funções podem ser declaradas com `async def` ou `def` normal.
+
+### Evento `startup`
+
+Para adicionar uma função que deve rodar antes da aplicação iniciar, declare-a com o evento `"startup"`:
+
+```Python hl_lines="8"
+{!../../../docs_src/events/tutorial001.py!}
+```
+
+Nesse caso, a função de manipulação de evento `startup` irá inicializar os itens do "banco de dados" (só um `dict`) com alguns valores.
+
+Você pode adicionar mais que uma função de manipulação de evento.
+
+E sua aplicação não irá começar a receber requisições até que todos os manipuladores de eventos de `startup` sejam concluídos.
+
+### Evento `shutdown`
+
+Para adicionar uma função que deve ser executada quando a aplicação estiver encerrando, declare ela com o evento `"shutdown"`:
+
+```Python hl_lines="6"
+{!../../../docs_src/events/tutorial002.py!}
+```
+
+Aqui, a função de manipulação de evento `shutdown` irá escrever uma linha de texto `"Application shutdown"` no arquivo `log.txt`.
+
+!!! info "Informação"
+ Na função `open()`, o `mode="a"` significa "acrescentar", então, a linha irá ser adicionada depois de qualquer coisa que esteja naquele arquivo, sem sobrescrever o conteúdo anterior.
+
+!!! tip "Dica"
+ Perceba que nesse caso nós estamos usando a função padrão do Python `open()` que interage com um arquivo.
+
+ Então, isso envolve I/O (input/output), que exige "esperar" que coisas sejam escritas em disco.
+
+ Mas `open()` não usa `async` e `await`.
+
+ Então, nós declaramos uma função de manipulação de evento com o padrão `def` ao invés de `async def`.
+
+### `startup` e `shutdown` juntos
+
+Há uma grande chance que a lógica para sua *inicialização* e *encerramento* esteja conectada, você pode querer iniciar alguma coisa e então finalizá-la, adquirir um recurso e então liberá-lo, etc.
+
+Fazendo isso em funções separadas que não compartilham lógica ou variáveis entre elas é mais difícil já que você precisa armazenar os valores em variáveis globais ou truques parecidos.
+
+Por causa disso, agora é recomendado em vez disso usar o `lifespan` como explicado acima.
+
+## Detalhes técnicos
+
+Só um detalhe técnico para nerds curiosos. 🤓
+
+Por baixo, na especificação técnica ASGI, essa é a parte do Protocolo Lifespan, e define eventos chamados `startup` e `shutdown`.
+
+!!! info "Informação"
+ Você pode ler mais sobre o manipulador `lifespan` do Starlette na Documentação do Lifespan Starlette.
+
+ Incluindo como manipular estado do lifespan que pode ser usado em outras áreas do seu código.
+
+## Sub Aplicações
+
+🚨 Tenha em mente que esses eventos de lifespan (de inicialização e desligamento) irão somente ser executados para a aplicação principal, não para [Sub Aplicações - Montagem](./sub-applications.md){.internal-link target=_blank}.
diff --git a/docs/pt/docs/index.md b/docs/pt/docs/index.md
index afc101ede..76668b4da 100644
--- a/docs/pt/docs/index.md
+++ b/docs/pt/docs/index.md
@@ -292,7 +292,7 @@ Agora vá para ../../../docs_src/body_multiple_params/tutorial001.py!}
+ ```Python hl_lines="17-19"
+ {!> ../../../docs_src/body_multiple_params/tutorial001_py310.py!}
```
-=== "Python 3.10 e superiores"
+=== "Python 3.6+"
- ```Python hl_lines="17-19"
- {!> ../../../docs_src/body_multiple_params/tutorial001_py310.py!}
+ ```Python hl_lines="19-21"
+ {!> ../../../docs_src/body_multiple_params/tutorial001.py!}
```
!!! nota
@@ -38,16 +38,16 @@ No exemplo anterior, as *operações de rota* esperariam um JSON no corpo conten
Mas você pode também declarar múltiplos parâmetros de corpo, por exemplo, `item` e `user`:
-=== "Python 3.6 e superiores"
+=== "Python 3.10+"
- ```Python hl_lines="22"
- {!> ../../../docs_src/body_multiple_params/tutorial002.py!}
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/body_multiple_params/tutorial002_py310.py!}
```
-=== "Python 3.10 e superiores"
+=== "Python 3.6+"
- ```Python hl_lines="20"
- {!> ../../../docs_src/body_multiple_params/tutorial002_py310.py!}
+ ```Python hl_lines="22"
+ {!> ../../../docs_src/body_multiple_params/tutorial002.py!}
```
Neste caso, o **FastAPI** perceberá que existe mais de um parâmetro de corpo na função (dois parâmetros que são modelos Pydantic).
@@ -87,13 +87,13 @@ Se você declará-lo como é, porque é um valor singular, o **FastAPI** assumir
Mas você pode instruir o **FastAPI** para tratá-lo como outra chave do corpo usando `Body`:
-=== "Python 3.6 e superiores"
+=== "Python 3.6+"
```Python hl_lines="22"
{!> ../../../docs_src/body_multiple_params/tutorial003.py!}
```
-=== "Python 3.10 e superiores"
+=== "Python 3.10+"
```Python hl_lines="20"
{!> ../../../docs_src/body_multiple_params/tutorial003_py310.py!}
@@ -137,16 +137,16 @@ q: str | None = None
Por exemplo:
-=== "Python 3.6 e superiores"
+=== "Python 3.10+"
- ```Python hl_lines="27"
- {!> ../../../docs_src/body_multiple_params/tutorial004.py!}
+ ```Python hl_lines="26"
+ {!> ../../../docs_src/body_multiple_params/tutorial004_py310.py!}
```
-=== "Python 3.10 e superiores"
+=== "Python 3.6+"
- ```Python hl_lines="26"
- {!> ../../../docs_src/body_multiple_params/tutorial004_py310.py!}
+ ```Python hl_lines="27"
+ {!> ../../../docs_src/body_multiple_params/tutorial004.py!}
```
!!! info "Informação"
@@ -166,16 +166,16 @@ item: Item = Body(embed=True)
como em:
-=== "Python 3.6 e superiores"
+=== "Python 3.10+"
- ```Python hl_lines="17"
- {!> ../../../docs_src/body_multiple_params/tutorial005.py!}
+ ```Python hl_lines="15"
+ {!> ../../../docs_src/body_multiple_params/tutorial005_py310.py!}
```
-=== "Python 3.10 e superiores"
+=== "Python 3.6+"
- ```Python hl_lines="15"
- {!> ../../../docs_src/body_multiple_params/tutorial005_py310.py!}
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/body_multiple_params/tutorial005.py!}
```
Neste caso o **FastAPI** esperará um corpo como:
diff --git a/docs/pt/docs/tutorial/body-nested-models.md b/docs/pt/docs/tutorial/body-nested-models.md
new file mode 100644
index 000000000..8ab77173e
--- /dev/null
+++ b/docs/pt/docs/tutorial/body-nested-models.md
@@ -0,0 +1,248 @@
+# Corpo - Modelos aninhados
+
+Com o **FastAPI**, você pode definir, validar, documentar e usar modelos profundamente aninhados de forma arbitrária (graças ao Pydantic).
+
+## Campos do tipo Lista
+
+Você pode definir um atributo como um subtipo. Por exemplo, uma `list` do Python:
+
+```Python hl_lines="14"
+{!../../../docs_src/body_nested_models/tutorial001.py!}
+```
+
+Isso fará com que tags seja uma lista de itens mesmo sem declarar o tipo dos elementos desta lista.
+
+## Campos do tipo Lista com um parâmetro de tipo
+
+Mas o Python tem uma maneira específica de declarar listas com tipos internos ou "parâmetros de tipo":
+
+### Importe `List` do typing
+
+Primeiramente, importe `List` do módulo `typing` que já vem por padrão no Python:
+
+```Python hl_lines="1"
+{!../../../docs_src/body_nested_models/tutorial002.py!}
+```
+
+### Declare a `List` com um parâmetro de tipo
+
+Para declarar tipos que têm parâmetros de tipo(tipos internos), como `list`, `dict`, `tuple`:
+
+* Importe os do modulo `typing`
+* Passe o(s) tipo(s) interno(s) como "parâmetros de tipo" usando colchetes: `[` e `]`
+
+```Python
+from typing import List
+
+my_list: List[str]
+```
+
+Essa é a sintaxe padrão do Python para declarações de tipo.
+
+Use a mesma sintaxe padrão para atributos de modelo com tipos internos.
+
+Portanto, em nosso exemplo, podemos fazer com que `tags` sejam especificamente uma "lista de strings":
+
+
+```Python hl_lines="14"
+{!../../../docs_src/body_nested_models/tutorial002.py!}
+```
+
+## Tipo "set"
+
+
+Mas então, quando nós pensamos mais, percebemos que as tags não devem se repetir, elas provavelmente devem ser strings únicas.
+
+E que o Python tem um tipo de dados especial para conjuntos de itens únicos, o `set`.
+
+Então podemos importar `Set` e declarar `tags` como um `set` de `str`s:
+
+
+```Python hl_lines="1 14"
+{!../../../docs_src/body_nested_models/tutorial003.py!}
+```
+
+Com isso, mesmo que você receba uma requisição contendo dados duplicados, ela será convertida em um conjunto de itens exclusivos.
+
+E sempre que você enviar esses dados como resposta, mesmo se a fonte tiver duplicatas, eles serão gerados como um conjunto de itens exclusivos.
+
+E também teremos anotações/documentação em conformidade.
+
+## Modelos aninhados
+
+Cada atributo de um modelo Pydantic tem um tipo.
+
+Mas esse tipo pode ser outro modelo Pydantic.
+
+Portanto, você pode declarar "objects" JSON profundamente aninhados com nomes, tipos e validações de atributos específicos.
+
+Tudo isso, aninhado arbitrariamente.
+
+### Defina um sub-modelo
+
+Por exemplo, nós podemos definir um modelo `Image`:
+
+```Python hl_lines="9-11"
+{!../../../docs_src/body_nested_models/tutorial004.py!}
+```
+
+### Use o sub-modelo como um tipo
+
+E então podemos usa-lo como o tipo de um atributo:
+
+```Python hl_lines="20"
+{!../../../docs_src/body_nested_models/tutorial004.py!}
+```
+
+Isso significa que o **FastAPI** vai esperar um corpo similar à:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2,
+ "tags": ["rock", "metal", "bar"],
+ "image": {
+ "url": "http://example.com/baz.jpg",
+ "name": "The Foo live"
+ }
+}
+```
+
+Novamente, apenas fazendo essa declaração, com o **FastAPI**, você ganha:
+
+* Suporte do editor de texto (compleção, etc), inclusive para modelos aninhados
+* Conversão de dados
+* Validação de dados
+* Documentação automatica
+
+## Tipos especiais e validação
+
+Além dos tipos singulares normais como `str`, `int`, `float`, etc. Você também pode usar tipos singulares mais complexos que herdam de `str`.
+
+Para ver todas as opções possíveis, cheque a documentação para ostipos exoticos do Pydantic. Você verá alguns exemplos no próximo capitulo.
+
+Por exemplo, no modelo `Image` nós temos um campo `url`, nós podemos declara-lo como um `HttpUrl` do Pydantic invés de como uma `str`:
+
+```Python hl_lines="4 10"
+{!../../../docs_src/body_nested_models/tutorial005.py!}
+```
+
+A string será verificada para se tornar uma URL válida e documentada no esquema JSON/1OpenAPI como tal.
+
+## Atributos como listas de submodelos
+
+Você também pode usar modelos Pydantic como subtipos de `list`, `set`, etc:
+
+```Python hl_lines="20"
+{!../../../docs_src/body_nested_models/tutorial006.py!}
+```
+
+Isso vai esperar(converter, validar, documentar, etc) um corpo JSON tal qual:
+
+```JSON hl_lines="11"
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2,
+ "tags": [
+ "rock",
+ "metal",
+ "bar"
+ ],
+ "images": [
+ {
+ "url": "http://example.com/baz.jpg",
+ "name": "The Foo live"
+ },
+ {
+ "url": "http://example.com/dave.jpg",
+ "name": "The Baz"
+ }
+ ]
+}
+```
+
+!!! Informação
+ Note como o campo `images` agora tem uma lista de objetos de image.
+
+## Modelos profundamente aninhados
+
+Você pode definir modelos profundamente aninhados de forma arbitrária:
+
+```Python hl_lines="9 14 20 23 27"
+{!../../../docs_src/body_nested_models/tutorial007.py!}
+```
+
+!!! Informação
+ Note como `Offer` tem uma lista de `Item`s, que por sua vez possui opcionalmente uma lista `Image`s
+
+## Corpos de listas puras
+
+Se o valor de primeiro nível do corpo JSON que você espera for um `array` do JSON (uma` lista` do Python), você pode declarar o tipo no parâmetro da função, da mesma forma que nos modelos do Pydantic:
+
+
+```Python
+images: List[Image]
+```
+
+como em:
+
+```Python hl_lines="15"
+{!../../../docs_src/body_nested_models/tutorial008.py!}
+```
+
+## Suporte de editor em todo canto
+
+E você obtém suporte do editor em todos os lugares.
+
+Mesmo para itens dentro de listas:
+
+
+
+Você não conseguiria este tipo de suporte de editor se estivesse trabalhando diretamente com `dict` em vez de modelos Pydantic.
+
+Mas você também não precisa se preocupar com eles, os dicts de entrada são convertidos automaticamente e sua saída é convertida automaticamente para JSON também.
+
+## Corpos de `dict`s arbitrários
+
+Você também pode declarar um corpo como um `dict` com chaves de algum tipo e valores de outro tipo.
+
+Sem ter que saber de antemão quais são os nomes de campos/atributos válidos (como seria o caso dos modelos Pydantic).
+
+Isso seria útil se você deseja receber chaves que ainda não conhece.
+
+---
+
+Outro caso útil é quando você deseja ter chaves de outro tipo, por exemplo, `int`.
+
+É isso que vamos ver aqui.
+
+Neste caso, você aceitaria qualquer `dict`, desde que tenha chaves` int` com valores `float`:
+
+```Python hl_lines="9"
+{!../../../docs_src/body_nested_models/tutorial009.py!}
+```
+
+!!! Dica
+ Leve em condideração que o JSON só suporta `str` como chaves.
+
+ Mas o Pydantic tem conversão automática de dados.
+
+ Isso significa que, embora os clientes da API só possam enviar strings como chaves, desde que essas strings contenham inteiros puros, o Pydantic irá convertê-los e validá-los.
+
+ E o `dict` que você recebe como `weights` terá, na verdade, chaves `int` e valores` float`.
+
+## Recapitulação
+
+Com **FastAPI** você tem a flexibilidade máxima fornecida pelos modelos Pydantic, enquanto seu código é mantido simples, curto e elegante.
+
+Mas com todos os benefícios:
+
+* Suporte do editor (compleção em todo canto!)
+* Conversão de dados (leia-se parsing/serialização)
+* Validação de dados
+* Documentação dos esquemas
+* Documentação automática
diff --git a/docs/pt/docs/tutorial/encoder.md b/docs/pt/docs/tutorial/encoder.md
new file mode 100644
index 000000000..bb4483fdc
--- /dev/null
+++ b/docs/pt/docs/tutorial/encoder.md
@@ -0,0 +1,42 @@
+# Codificador Compatível com JSON
+
+Existem alguns casos em que você pode precisar converter um tipo de dados (como um modelo Pydantic) para algo compatível com JSON (como um `dict`, `list`, etc).
+
+Por exemplo, se você precisar armazená-lo em um banco de dados.
+
+Para isso, **FastAPI** fornece uma função `jsonable_encoder()`.
+
+## Usando a função `jsonable_encoder`
+
+Vamos imaginar que você tenha um banco de dados `fake_db` que recebe apenas dados compatíveis com JSON.
+
+Por exemplo, ele não recebe objetos `datetime`, pois estes objetos não são compatíveis com JSON.
+
+Então, um objeto `datetime` teria que ser convertido em um `str` contendo os dados no formato ISO.
+
+Da mesma forma, este banco de dados não receberia um modelo Pydantic (um objeto com atributos), apenas um `dict`.
+
+Você pode usar a função `jsonable_encoder` para resolver isso.
+
+A função recebe um objeto, como um modelo Pydantic e retorna uma versão compatível com JSON:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="4 21"
+ {!> ../../../docs_src/encoder/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="5 22"
+ {!> ../../../docs_src/encoder/tutorial001.py!}
+ ```
+
+Neste exemplo, ele converteria o modelo Pydantic em um `dict`, e o `datetime` em um `str`.
+
+O resultado de chamar a função é algo que pode ser codificado com o padrão do Python `json.dumps()`.
+
+A função não retorna um grande `str` contendo os dados no formato JSON (como uma string). Mas sim, retorna uma estrutura de dados padrão do Python (por exemplo, um `dict`) com valores e subvalores compatíveis com JSON.
+
+!!! nota
+ `jsonable_encoder` é realmente usado pelo **FastAPI** internamente para converter dados. Mas também é útil em muitos outros cenários.
diff --git a/docs/pt/docs/tutorial/extra-models.md b/docs/pt/docs/tutorial/extra-models.md
new file mode 100644
index 000000000..dd5407eb2
--- /dev/null
+++ b/docs/pt/docs/tutorial/extra-models.md
@@ -0,0 +1,252 @@
+# Modelos Adicionais
+
+Continuando com o exemplo anterior, será comum ter mais de um modelo relacionado.
+
+Isso é especialmente o caso para modelos de usuários, porque:
+
+* O **modelo de entrada** precisa ser capaz de ter uma senha.
+* O **modelo de saída** não deve ter uma senha.
+* O **modelo de banco de dados** provavelmente precisaria ter uma senha criptografada.
+
+!!! danger
+ Nunca armazene senhas em texto simples dos usuários. Sempre armazene uma "hash segura" que você pode verificar depois.
+
+ Se não souber, você aprenderá o que é uma "senha hash" nos [capítulos de segurança](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}.
+
+## Múltiplos modelos
+
+Aqui está uma ideia geral de como os modelos poderiam parecer com seus campos de senha e os lugares onde são usados:
+
+=== "Python 3.6 and above"
+
+ ```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41"
+ {!> ../../../docs_src/extra_models/tutorial001.py!}
+ ```
+
+=== "Python 3.10 and above"
+
+ ```Python hl_lines="7 9 14 20 22 27-28 31-33 38-39"
+ {!> ../../../docs_src/extra_models/tutorial001_py310.py!}
+ ```
+
+### Sobre `**user_in.dict()`
+
+#### O `.dict()` do Pydantic
+
+`user_in` é um modelo Pydantic da classe `UserIn`.
+
+Os modelos Pydantic possuem um método `.dict()` que retorna um `dict` com os dados do modelo.
+
+Então, se criarmos um objeto Pydantic `user_in` como:
+
+```Python
+user_in = UserIn(username="john", password="secret", email="john.doe@example.com")
+```
+
+e depois chamarmos:
+
+```Python
+user_dict = user_in.dict()
+```
+
+agora temos um `dict` com os dados na variável `user_dict` (é um `dict` em vez de um objeto de modelo Pydantic).
+
+E se chamarmos:
+
+```Python
+print(user_dict)
+```
+
+teríamos um `dict` Python com:
+
+```Python
+{
+ 'username': 'john',
+ 'password': 'secret',
+ 'email': 'john.doe@example.com',
+ 'full_name': None,
+}
+```
+
+#### Desembrulhando um `dict`
+
+Se tomarmos um `dict` como `user_dict` e passarmos para uma função (ou classe) com `**user_dict`, o Python irá "desembrulhá-lo". Ele passará as chaves e valores do `user_dict` diretamente como argumentos chave-valor.
+
+Então, continuando com o `user_dict` acima, escrevendo:
+
+```Python
+UserInDB(**user_dict)
+```
+
+Resultaria em algo equivalente a:
+
+```Python
+UserInDB(
+ username="john",
+ password="secret",
+ email="john.doe@example.com",
+ full_name=None,
+)
+```
+
+Ou mais exatamente, usando `user_dict` diretamente, com qualquer conteúdo que ele possa ter no futuro:
+
+```Python
+UserInDB(
+ username = user_dict["username"],
+ password = user_dict["password"],
+ email = user_dict["email"],
+ full_name = user_dict["full_name"],
+)
+```
+
+#### Um modelo Pydantic a partir do conteúdo de outro
+
+Como no exemplo acima, obtivemos o `user_dict` a partir do `user_in.dict()`, este código:
+
+```Python
+user_dict = user_in.dict()
+UserInDB(**user_dict)
+```
+
+seria equivalente a:
+
+```Python
+UserInDB(**user_in.dict())
+```
+
+...porque `user_in.dict()` é um `dict`, e depois fazemos o Python "desembrulhá-lo" passando-o para UserInDB precedido por `**`.
+
+Então, obtemos um modelo Pydantic a partir dos dados em outro modelo Pydantic.
+
+#### Desembrulhando um `dict` e palavras-chave extras
+
+E, então, adicionando o argumento de palavra-chave extra `hashed_password=hashed_password`, como em:
+
+```Python
+UserInDB(**user_in.dict(), hashed_password=hashed_password)
+```
+
+...acaba sendo como:
+
+```Python
+UserInDB(
+ username = user_dict["username"],
+ password = user_dict["password"],
+ email = user_dict["email"],
+ full_name = user_dict["full_name"],
+ hashed_password = hashed_password,
+)
+```
+
+!!! warning
+ As funções adicionais de suporte são apenas para demonstração de um fluxo possível dos dados, mas é claro que elas não fornecem segurança real.
+
+## Reduzir duplicação
+
+Reduzir a duplicação de código é uma das ideias principais no **FastAPI**.
+
+A duplicação de código aumenta as chances de bugs, problemas de segurança, problemas de desincronização de código (quando você atualiza em um lugar, mas não em outros), etc.
+
+E esses modelos estão compartilhando muitos dos dados e duplicando nomes e tipos de atributos.
+
+Nós poderíamos fazer melhor.
+
+Podemos declarar um modelo `UserBase` que serve como base para nossos outros modelos. E então podemos fazer subclasses desse modelo que herdam seus atributos (declarações de tipo, validação, etc.).
+
+Toda conversão de dados, validação, documentação, etc. ainda funcionará normalmente.
+
+Dessa forma, podemos declarar apenas as diferenças entre os modelos (com `password` em texto claro, com `hashed_password` e sem senha):
+
+=== "Python 3.6 and above"
+
+ ```Python hl_lines="9 15-16 19-20 23-24"
+ {!> ../../../docs_src/extra_models/tutorial002.py!}
+ ```
+
+=== "Python 3.10 and above"
+
+ ```Python hl_lines="7 13-14 17-18 21-22"
+ {!> ../../../docs_src/extra_models/tutorial002_py310.py!}
+ ```
+
+## `Union` ou `anyOf`
+
+Você pode declarar uma resposta como o `Union` de dois tipos, o que significa que a resposta seria qualquer um dos dois.
+
+Isso será definido no OpenAPI com `anyOf`.
+
+Para fazer isso, use a dica de tipo padrão do Python `typing.Union`:
+
+!!! note
+ Ao definir um `Union`, inclua o tipo mais específico primeiro, seguido pelo tipo menos específico. No exemplo abaixo, o tipo mais específico `PlaneItem` vem antes de `CarItem` em `Union[PlaneItem, CarItem]`.
+
+=== "Python 3.6 and above"
+
+ ```Python hl_lines="1 14-15 18-20 33"
+ {!> ../../../docs_src/extra_models/tutorial003.py!}
+ ```
+
+=== "Python 3.10 and above"
+
+ ```Python hl_lines="1 14-15 18-20 33"
+ {!> ../../../docs_src/extra_models/tutorial003_py310.py!}
+ ```
+
+### `Union` no Python 3.10
+
+Neste exemplo, passamos `Union[PlaneItem, CarItem]` como o valor do argumento `response_model`.
+
+Dado que estamos passando-o como um **valor para um argumento** em vez de colocá-lo em uma **anotação de tipo**, precisamos usar `Union` mesmo no Python 3.10.
+
+Se estivesse em uma anotação de tipo, poderíamos ter usado a barra vertical, como:
+
+```Python
+some_variable: PlaneItem | CarItem
+```
+
+Mas se colocarmos isso em `response_model=PlaneItem | CarItem` teríamos um erro, pois o Python tentaria executar uma **operação inválida** entre `PlaneItem` e `CarItem` em vez de interpretar isso como uma anotação de tipo.
+
+## Lista de modelos
+
+Da mesma forma, você pode declarar respostas de listas de objetos.
+
+Para isso, use o padrão Python `typing.List` (ou simplesmente `list` no Python 3.9 e superior):
+
+=== "Python 3.6 and above"
+
+ ```Python hl_lines="1 20"
+ {!> ../../../docs_src/extra_models/tutorial004.py!}
+ ```
+
+=== "Python 3.9 and above"
+
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/extra_models/tutorial004_py39.py!}
+ ```
+
+## Resposta com `dict` arbitrário
+
+Você também pode declarar uma resposta usando um simples `dict` arbitrário, declarando apenas o tipo das chaves e valores, sem usar um modelo Pydantic.
+
+Isso é útil se você não souber os nomes de campo / atributo válidos (que seriam necessários para um modelo Pydantic) antecipadamente.
+
+Neste caso, você pode usar `typing.Dict` (ou simplesmente dict no Python 3.9 e superior):
+
+=== "Python 3.6 and above"
+
+ ```Python hl_lines="1 8"
+ {!> ../../../docs_src/extra_models/tutorial005.py!}
+ ```
+
+=== "Python 3.9 and above"
+
+ ```Python hl_lines="6"
+ {!> ../../../docs_src/extra_models/tutorial005_py39.py!}
+ ```
+
+## Em resumo
+
+Use vários modelos Pydantic e herde livremente para cada caso.
+
+Não é necessário ter um único modelo de dados por entidade se essa entidade precisar ter diferentes "estados". No caso da "entidade" de usuário com um estado que inclui `password`, `password_hash` e sem senha.
diff --git a/docs/pt/docs/tutorial/header-params.md b/docs/pt/docs/tutorial/header-params.md
index 94ee784cd..bc8843327 100644
--- a/docs/pt/docs/tutorial/header-params.md
+++ b/docs/pt/docs/tutorial/header-params.md
@@ -6,16 +6,16 @@ Você pode definir parâmetros de Cabeçalho da mesma maneira que define paramê
Primeiro importe `Header`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="3"
- {!> ../../../docs_src/header_params/tutorial001.py!}
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/header_params/tutorial001_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="1"
- {!> ../../../docs_src/header_params/tutorial001_py310.py!}
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/header_params/tutorial001.py!}
```
## Declare parâmetros de `Header`
@@ -24,16 +24,16 @@ Então declare os paramêtros de cabeçalho usando a mesma estrutura que em `Pat
O primeiro valor é o valor padrão, você pode passar todas as validações adicionais ou parâmetros de anotação:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="9"
- {!> ../../../docs_src/header_params/tutorial001.py!}
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/header_params/tutorial001_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="7"
- {!> ../../../docs_src/header_params/tutorial001_py310.py!}
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial001.py!}
```
!!! note "Detalhes Técnicos"
@@ -60,16 +60,16 @@ Portanto, você pode usar `user_agent` como faria normalmente no código Python,
Se por algum motivo você precisar desabilitar a conversão automática de sublinhados para hífens, defina o parâmetro `convert_underscores` de `Header` para `False`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="10"
- {!> ../../../docs_src/header_params/tutorial002.py!}
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/header_params/tutorial002_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="8"
- {!> ../../../docs_src/header_params/tutorial002_py310.py!}
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/header_params/tutorial002.py!}
```
!!! warning "Aviso"
@@ -85,22 +85,22 @@ Você receberá todos os valores do cabeçalho duplicado como uma `list` Python.
Por exemplo, para declarar um cabeçalho de `X-Token` que pode aparecer mais de uma vez, você pode escrever:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="9"
- {!> ../../../docs_src/header_params/tutorial003.py!}
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/header_params/tutorial003_py310.py!}
```
-=== "Python 3.9 and above"
+=== "Python 3.9+"
```Python hl_lines="9"
{!> ../../../docs_src/header_params/tutorial003_py39.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="7"
- {!> ../../../docs_src/header_params/tutorial003_py310.py!}
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial003.py!}
```
Se você se comunicar com essa *operação de caminho* enviando dois cabeçalhos HTTP como:
diff --git a/docs/pt/docs/tutorial/path-operation-configuration.md b/docs/pt/docs/tutorial/path-operation-configuration.md
new file mode 100644
index 000000000..e0a23f665
--- /dev/null
+++ b/docs/pt/docs/tutorial/path-operation-configuration.md
@@ -0,0 +1,180 @@
+# Configuração da Operação de Rota
+
+Existem vários parâmetros que você pode passar para o seu *decorador de operação de rota* para configurá-lo.
+
+!!! warning "Aviso"
+ Observe que esses parâmetros são passados diretamente para o *decorador de operação de rota*, não para a sua *função de operação de rota*.
+
+## Código de Status da Resposta
+
+Você pode definir o `status_code` (HTTP) para ser usado na resposta da sua *operação de rota*.
+
+Você pode passar diretamente o código `int`, como `404`.
+
+Mas se você não se lembrar o que cada código numérico significa, pode usar as constantes de atalho em `status`:
+
+=== "Python 3.6 and above"
+
+ ```Python hl_lines="3 17"
+ {!> ../../../docs_src/path_operation_configuration/tutorial001.py!}
+ ```
+
+=== "Python 3.9 and above"
+
+ ```Python hl_lines="3 17"
+ {!> ../../../docs_src/path_operation_configuration/tutorial001_py39.py!}
+ ```
+
+=== "Python 3.10 and above"
+
+ ```Python hl_lines="1 15"
+ {!> ../../../docs_src/path_operation_configuration/tutorial001_py310.py!}
+ ```
+
+Esse código de status será usado na resposta e será adicionado ao esquema OpenAPI.
+
+!!! note "Detalhes Técnicos"
+ Você também poderia usar `from starlette import status`.
+
+ **FastAPI** fornece o mesmo `starlette.status` como `fastapi.status` apenas como uma conveniência para você, o desenvolvedor. Mas vem diretamente do Starlette.
+
+## Tags
+
+Você pode adicionar tags para sua *operação de rota*, passe o parâmetro `tags` com uma `list` de `str` (comumente apenas um `str`):
+
+=== "Python 3.6 and above"
+
+ ```Python hl_lines="17 22 27"
+ {!> ../../../docs_src/path_operation_configuration/tutorial002.py!}
+ ```
+
+=== "Python 3.9 and above"
+
+ ```Python hl_lines="17 22 27"
+ {!> ../../../docs_src/path_operation_configuration/tutorial002_py39.py!}
+ ```
+
+=== "Python 3.10 and above"
+
+ ```Python hl_lines="15 20 25"
+ {!> ../../../docs_src/path_operation_configuration/tutorial002_py310.py!}
+ ```
+
+Eles serão adicionados ao esquema OpenAPI e usados pelas interfaces de documentação automática:
+
+
+
+### Tags com Enums
+
+Se você tem uma grande aplicação, você pode acabar acumulando **várias tags**, e você gostaria de ter certeza de que você sempre usa a **mesma tag** para *operações de rota* relacionadas.
+
+Nestes casos, pode fazer sentido armazenar as tags em um `Enum`.
+
+**FastAPI** suporta isso da mesma maneira que com strings simples:
+
+```Python hl_lines="1 8-10 13 18"
+{!../../../docs_src/path_operation_configuration/tutorial002b.py!}
+```
+
+## Resumo e descrição
+
+Você pode adicionar um `summary` e uma `description`:
+
+=== "Python 3.6 and above"
+
+ ```Python hl_lines="20-21"
+ {!> ../../../docs_src/path_operation_configuration/tutorial003.py!}
+ ```
+
+=== "Python 3.9 and above"
+
+ ```Python hl_lines="20-21"
+ {!> ../../../docs_src/path_operation_configuration/tutorial003_py39.py!}
+ ```
+
+=== "Python 3.10 and above"
+
+ ```Python hl_lines="18-19"
+ {!> ../../../docs_src/path_operation_configuration/tutorial003_py310.py!}
+ ```
+
+## Descrição do docstring
+
+Como as descrições tendem a ser longas e cobrir várias linhas, você pode declarar a descrição da *operação de rota* na docstring da função e o **FastAPI** irá lê-la de lá.
+
+Você pode escrever Markdown na docstring, ele será interpretado e exibido corretamente (levando em conta a indentação da docstring).
+
+=== "Python 3.6 and above"
+
+ ```Python hl_lines="19-27"
+ {!> ../../../docs_src/path_operation_configuration/tutorial004.py!}
+ ```
+
+=== "Python 3.9 and above"
+
+ ```Python hl_lines="19-27"
+ {!> ../../../docs_src/path_operation_configuration/tutorial004_py39.py!}
+ ```
+
+=== "Python 3.10 and above"
+
+ ```Python hl_lines="17-25"
+ {!> ../../../docs_src/path_operation_configuration/tutorial004_py310.py!}
+ ```
+
+Ela será usada nas documentações interativas:
+
+
+
+
+## Descrição da resposta
+
+Você pode especificar a descrição da resposta com o parâmetro `response_description`:
+
+=== "Python 3.6 and above"
+
+ ```Python hl_lines="21"
+ {!> ../../../docs_src/path_operation_configuration/tutorial005.py!}
+ ```
+
+=== "Python 3.9 and above"
+
+ ```Python hl_lines="21"
+ {!> ../../../docs_src/path_operation_configuration/tutorial005_py39.py!}
+ ```
+
+=== "Python 3.10 and above"
+
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/path_operation_configuration/tutorial005_py310.py!}
+ ```
+
+!!! info "Informação"
+ Note que `response_description` se refere especificamente à resposta, a `description` se refere à *operação de rota* em geral.
+
+!!! check
+ OpenAPI especifica que cada *operação de rota* requer uma descrição de resposta.
+
+ Então, se você não fornecer uma, o **FastAPI** irá gerar automaticamente uma de "Resposta bem-sucedida".
+
+
+
+## Depreciar uma *operação de rota*
+
+Se você precisar marcar uma *operação de rota* como descontinuada, mas sem removê-la, passe o parâmetro `deprecated`:
+
+```Python hl_lines="16"
+{!../../../docs_src/path_operation_configuration/tutorial006.py!}
+```
+
+Ela será claramente marcada como descontinuada nas documentações interativas:
+
+
+
+Verifique como *operações de rota* descontinuadas e não descontinuadas se parecem:
+
+
+
+## Resumindo
+
+Você pode configurar e adicionar metadados para suas *operações de rota* facilmente passando parâmetros para os *decoradores de operação de rota*.
diff --git a/docs/pt/docs/tutorial/path-params-numeric-validations.md b/docs/pt/docs/tutorial/path-params-numeric-validations.md
index f478fd190..ec9b74b30 100644
--- a/docs/pt/docs/tutorial/path-params-numeric-validations.md
+++ b/docs/pt/docs/tutorial/path-params-numeric-validations.md
@@ -6,16 +6,16 @@ Do mesmo modo que você pode declarar mais validações e metadados para parâme
Primeiro, importe `Path` de `fastapi`:
-=== "Python 3.6 e superiores"
+=== "Python 3.10+"
- ```Python hl_lines="3"
- {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
```
-=== "Python 3.10 e superiores"
+=== "Python 3.6+"
- ```Python hl_lines="1"
- {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
```
## Declare metadados
@@ -24,16 +24,16 @@ Você pode declarar todos os parâmetros da mesma maneira que na `Query`.
Por exemplo para declarar um valor de metadado `title` para o parâmetro de rota `item_id` você pode digitar:
-=== "Python 3.6 e superiores"
+=== "Python 3.10+"
- ```Python hl_lines="10"
- {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
```
-=== "Python 3.10 e superiores"
+=== "Python 3.6+"
- ```Python hl_lines="8"
- {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
```
!!! note "Nota"
diff --git a/docs/pt/docs/tutorial/query-params.md b/docs/pt/docs/tutorial/query-params.md
index 189724396..3ada4fd21 100644
--- a/docs/pt/docs/tutorial/query-params.md
+++ b/docs/pt/docs/tutorial/query-params.md
@@ -63,16 +63,16 @@ Os valores dos parâmetros na sua função serão:
Da mesma forma, você pode declarar parâmetros de consulta opcionais, definindo o valor padrão para `None`:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="9"
- {!> ../../../docs_src/query_params/tutorial002.py!}
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params/tutorial002_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="7"
- {!> ../../../docs_src/query_params/tutorial002_py310.py!}
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params/tutorial002.py!}
```
Nesse caso, o parâmetro da função `q` será opcional, e `None` será o padrão.
@@ -85,16 +85,16 @@ Nesse caso, o parâmetro da função `q` será opcional, e `None` será o padrã
Você também pode declarar tipos `bool`, e eles serão convertidos:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="9"
- {!> ../../../docs_src/query_params/tutorial003.py!}
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params/tutorial003_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="7"
- {!> ../../../docs_src/query_params/tutorial003_py310.py!}
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params/tutorial003.py!}
```
Nesse caso, se você for para:
@@ -137,16 +137,16 @@ E você não precisa declarar eles em nenhuma ordem específica.
Eles serão detectados pelo nome:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="8 10"
- {!> ../../../docs_src/query_params/tutorial004.py!}
+ ```Python hl_lines="6 8"
+ {!> ../../../docs_src/query_params/tutorial004_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="6 8"
- {!> ../../../docs_src/query_params/tutorial004_py310.py!}
+ ```Python hl_lines="8 10"
+ {!> ../../../docs_src/query_params/tutorial004.py!}
```
## Parâmetros de consulta obrigatórios
@@ -203,17 +203,18 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
E claro, você pode definir alguns parâmetros como obrigatórios, alguns possuindo um valor padrão, e outros sendo totalmente opcionais:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="10"
- {!> ../../../docs_src/query_params/tutorial006.py!}
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params/tutorial006_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="8"
- {!> ../../../docs_src/query_params/tutorial006_py310.py!}
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params/tutorial006.py!}
```
+
Nesse caso, existem 3 parâmetros de consulta:
* `needy`, um `str` obrigatório.
diff --git a/docs/pt/docs/tutorial/static-files.md b/docs/pt/docs/tutorial/static-files.md
new file mode 100644
index 000000000..009158fc6
--- /dev/null
+++ b/docs/pt/docs/tutorial/static-files.md
@@ -0,0 +1,39 @@
+# Arquivos Estáticos
+
+Você pode servir arquivos estáticos automaticamente de um diretório usando `StaticFiles`.
+
+## Use `StaticFiles`
+
+* Importe `StaticFiles`.
+* "Monte" uma instância de `StaticFiles()` em um caminho específico.
+
+```Python hl_lines="2 6"
+{!../../../docs_src/static_files/tutorial001.py!}
+```
+
+!!! note "Detalhes técnicos"
+ Você também pode usar `from starlette.staticfiles import StaticFiles`.
+
+ O **FastAPI** fornece o mesmo que `starlette.staticfiles` como `fastapi.staticfiles` apenas como uma conveniência para você, o desenvolvedor. Mas na verdade vem diretamente da Starlette.
+
+### O que é "Montagem"
+
+"Montagem" significa adicionar um aplicativo completamente "independente" em uma rota específica, que então cuida de todas as subrotas.
+
+Isso é diferente de usar um `APIRouter`, pois um aplicativo montado é completamente independente. A OpenAPI e a documentação do seu aplicativo principal não incluirão nada do aplicativo montado, etc.
+
+Você pode ler mais sobre isso no **Guia Avançado do Usuário**.
+
+## Detalhes
+
+O primeiro `"/static"` refere-se à subrota em que este "subaplicativo" será "montado". Portanto, qualquer caminho que comece com `"/static"` será tratado por ele.
+
+O `directory="static"` refere-se ao nome do diretório que contém seus arquivos estáticos.
+
+O `name="static"` dá a ela um nome que pode ser usado internamente pelo FastAPI.
+
+Todos esses parâmetros podem ser diferentes de "`static`", ajuste-os de acordo com as necessidades e detalhes específicos de sua própria aplicação.
+
+## Mais informações
+
+Para mais detalhes e opções, verifique Starlette's docs about Static Files.
diff --git a/docs/pt/mkdocs.yml b/docs/pt/mkdocs.yml
index 0858de062..023944618 100644
--- a/docs/pt/mkdocs.yml
+++ b/docs/pt/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -68,20 +73,26 @@ nav:
- tutorial/body.md
- tutorial/body-multiple-params.md
- tutorial/body-fields.md
+ - tutorial/body-nested-models.md
- tutorial/extra-data-types.md
+ - tutorial/extra-models.md
- tutorial/query-params-str-validations.md
- tutorial/path-params-numeric-validations.md
+ - tutorial/path-operation-configuration.md
- tutorial/cookie-params.md
- tutorial/header-params.md
- tutorial/response-status-code.md
- tutorial/request-forms.md
- tutorial/request-forms-and-files.md
- tutorial/handling-errors.md
+ - tutorial/encoder.md
- Segurança:
- tutorial/security/index.md
- tutorial/background-tasks.md
+ - tutorial/static-files.md
- Guia de Usuário Avançado:
- advanced/index.md
+ - advanced/events.md
- Implantação:
- deployment/index.md
- deployment/versions.md
@@ -115,7 +126,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -136,8 +147,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -146,6 +161,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -154,6 +171,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -166,6 +185,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/ru/docs/alternatives.md b/docs/ru/docs/alternatives.md
new file mode 100644
index 000000000..9e3c497d1
--- /dev/null
+++ b/docs/ru/docs/alternatives.md
@@ -0,0 +1,460 @@
+# Альтернативы, источники вдохновения и сравнения
+
+Что вдохновило на создание **FastAPI**, сравнение его с альтернативами и чему он научился у них.
+
+## Введение
+
+**FastAPI** не существовал бы, если б не было более ранних работ других людей.
+
+Они создали большое количество инструментов, которые вдохновили меня на создание **FastAPI**.
+
+Я всячески избегал создания нового фреймворка в течение нескольких лет.
+Сначала я пытался собрать все нужные функции, которые ныне есть в **FastAPI**, используя множество различных фреймворков, плагинов и инструментов.
+
+Но в какой-то момент не осталось другого выбора, кроме как создать что-то, что предоставляло бы все эти функции сразу.
+Взять самые лучшие идеи из предыдущих инструментов и, используя новые возможности Python (которых не было до версии 3.6, то есть подсказки типов), объединить их.
+
+## Предшествующие инструменты
+
+### Django
+
+Это самый популярный Python-фреймворк, и он пользуется доверием.
+Он используется для создания проектов типа Instagram.
+
+Django довольно тесно связан с реляционными базами данных (такими как MySQL или PostgreSQL), потому использовать NoSQL базы данных (например, Couchbase, MongoDB, Cassandra и т.п.) в качестве основного хранилища данных - непросто.
+
+Он был создан для генерации HTML-страниц на сервере, а не для создания API, используемых современными веб-интерфейсами (React, Vue.js, Angular и т.п.) или другими системами (например, IoT) взаимодействующими с сервером.
+
+### Django REST Framework
+
+Фреймворк Django REST был создан, как гибкий инструментарий для создания веб-API на основе Django.
+
+DRF использовался многими компаниями, включая Mozilla, Red Hat и Eventbrite.
+
+Это был один из первых примеров **автоматического документирования API** и это была одна из первых идей, вдохновивших на создание **FastAPI**.
+
+!!! note "Заметка"
+ Django REST Framework был создан Tom Christie.
+ Он же создал Starlette и Uvicorn, на которых основан **FastAPI**.
+
+!!! check "Идея для **FastAPI**"
+ Должно быть автоматическое создание документации API с пользовательским веб-интерфейсом.
+
+### Flask
+
+Flask - это "микрофреймворк", в нём нет интеграции с базами данных и многих других вещей, которые предустановлены в Django.
+
+Его простота и гибкость дают широкие возможности, такие как использование баз данных NoSQL в качестве основной системы хранения данных.
+
+Он очень прост, его изучение интуитивно понятно, хотя в некоторых местах документация довольно техническая.
+
+Flask часто используется и для приложений, которым не нужна база данных, настройки прав доступа для пользователей и прочие из множества функций, предварительно встроенных в Django.
+Хотя многие из этих функций могут быть добавлены с помощью плагинов.
+
+Такое разделение на части и то, что это "микрофреймворк", который можно расширить, добавляя необходимые возможности, было ключевой особенностью, которую я хотел сохранить.
+
+Простота Flask, показалась мне подходящей для создания API.
+Но ещё нужно было найти "Django REST Framework" для Flask.
+
+!!! check "Идеи для **FastAPI**"
+ Это будет микрофреймворк. К нему легко будет добавить необходимые инструменты и части.
+
+ Должна быть простая и лёгкая в использовании система маршрутизации запросов.
+
+
+### Requests
+
+На самом деле **FastAPI** не является альтернативой **Requests**.
+Их область применения очень разная.
+
+В принципе, можно использовать Requests *внутри* приложения FastAPI.
+
+Но всё же я использовал в FastAPI некоторые идеи из Requests.
+
+**Requests** - это библиотека для взаимодействия с API в качестве клиента,
+в то время как **FastAPI** - это библиотека для *создания* API (то есть сервера).
+
+Они, так или иначе, диаметрально противоположны и дополняют друг друга.
+
+Requests имеет очень простой и понятный дизайн, очень прост в использовании и имеет разумные значения по умолчанию.
+И в то же время он очень мощный и настраиваемый.
+
+Вот почему на официальном сайте написано:
+
+> Requests - один из самых загружаемых пакетов Python всех времен
+
+
+Использовать его очень просто. Например, чтобы выполнить запрос `GET`, Вы бы написали:
+
+```Python
+response = requests.get("http://example.com/some/url")
+```
+
+Противоположная *операция пути* в FastAPI может выглядеть следующим образом:
+
+```Python hl_lines="1"
+@app.get("/some/url")
+def read_url():
+ return {"message": "Hello World"}
+```
+
+Глядите, как похоже `requests.get(...)` и `@app.get(...)`.
+
+!!! check "Идеи для **FastAPI**"
+ * Должен быть простой и понятный API.
+ * Нужно использовать названия HTTP-методов (операций) для упрощения понимания происходящего.
+ * Должны быть разумные настройки по умолчанию и широкие возможности их кастомизации.
+
+
+### Swagger / OpenAPI
+
+Главной функцией, которую я хотел унаследовать от Django REST Framework, была автоматическая документация API.
+
+Но потом я обнаружил, что существует стандарт документирования API, использующий JSON (или YAML, расширение JSON) под названием Swagger.
+
+И к нему уже был создан пользовательский веб-интерфейс.
+Таким образом, возможность генерировать документацию Swagger для API позволила бы использовать этот интерфейс.
+
+В какой-то момент Swagger был передан Linux Foundation и переименован в OpenAPI.
+
+Вот почему, когда говорят о версии 2.0, обычно говорят "Swagger", а для версии 3+ "OpenAPI".
+
+!!! check "Идеи для **FastAPI**"
+ Использовать открытые стандарты для спецификаций API вместо самодельных схем.
+
+ Совместимость с основанными на стандартах пользовательскими интерфейсами:
+
+ * Swagger UI
+ * ReDoc
+
+ Они были выбраны за популярность и стабильность.
+ Но сделав беглый поиск, Вы можете найти десятки альтернативных пользовательских интерфейсов для OpenAPI, которые Вы можете использовать с **FastAPI**.
+
+### REST фреймворки для Flask
+
+Существует несколько REST фреймворков для Flask, но потратив время и усилия на их изучение, я обнаружил, что многие из них не обновляются или заброшены и имеют нерешённые проблемы из-за которых они непригодны к использованию.
+
+### Marshmallow
+
+Одной из основных функций, необходимых системам API, является "сериализация" данных, то есть преобразование данных из кода (Python) во что-то, что может быть отправлено по сети.
+Например, превращение объекта содержащего данные из базы данных в объект JSON, конвертация объекта `datetime` в строку и т.п.
+
+Еще одна важная функция, необходимая API — проверка данных, позволяющая убедиться, что данные действительны и соответствуют заданным параметрам.
+Как пример, можно указать, что ожидаются данные типа `int`, а не какая-то произвольная строка.
+Это особенно полезно для входящих данных.
+
+Без системы проверки данных Вам пришлось бы прописывать все проверки вручную.
+
+Именно для обеспечения этих функций и была создана Marshmallow.
+Это отличная библиотека и я много раз пользовался ею раньше.
+
+Но она была создана до того, как появились подсказки типов Python.
+Итак, чтобы определить каждую схему,
+Вам нужно использовать определенные утилиты и классы, предоставляемые Marshmallow.
+
+!!! check "Идея для **FastAPI**"
+ Использовать код программы для автоматического создания "схем", определяющих типы данных и их проверку.
+
+### Webargs
+
+Другая немаловажная функция API - парсинг данных из входящих запросов.
+
+Webargs - это инструмент, который был создан для этого и поддерживает несколько фреймворков, включая Flask.
+
+Для проверки данных он использует Marshmallow и создан теми же авторами.
+
+Это превосходный инструмент и я тоже часто пользовался им до **FastAPI**.
+
+!!! info "Информация"
+ Webargs бы создан разработчиками Marshmallow.
+
+!!! check "Идея для **FastAPI**"
+ Должна быть автоматическая проверка входных данных.
+
+### APISpec
+
+Marshmallow и Webargs осуществляют проверку, анализ и сериализацию данных как плагины.
+
+Но документации API всё ещё не было. Тогда был создан APISpec.
+
+Это плагин для множества фреймворков, в том числе и для Starlette.
+
+Он работает так - Вы записываете определение схем, используя формат YAML, внутри докстринга каждой функции, обрабатывающей маршрут.
+
+Используя эти докстринги, он генерирует схему OpenAPI.
+
+Так это работает для Flask, Starlette, Responder и т.п.
+
+Но теперь у нас возникает новая проблема - наличие постороннего микро-синтаксиса внутри кода Python (большие YAML).
+
+Редактор кода не особо может помочь в такой парадигме.
+А изменив какие-то параметры или схемы для Marshmallow можно забыть отредактировать докстринг с YAML и сгенерированная схема становится недействительной.
+
+!!! info "Информация"
+ APISpec тоже был создан авторами Marshmallow.
+
+!!! check "Идея для **FastAPI**"
+ Необходима поддержка открытого стандарта для API - OpenAPI.
+
+### Flask-apispec
+
+Это плагин для Flask, который связан с Webargs, Marshmallow и APISpec.
+
+Он получает информацию от Webargs и Marshmallow, а затем использует APISpec для автоматического создания схемы OpenAPI.
+
+Это отличный, но крайне недооценённый инструмент.
+Он должен быть более популярен, чем многие плагины для Flask.
+Возможно, это связано с тем, что его документация слишком скудна и абстрактна.
+
+Он избавил от необходимости писать чужеродный синтаксис YAML внутри докстрингов.
+
+Такое сочетание Flask, Flask-apispec, Marshmallow и Webargs было моим любимым стеком при построении бэкенда до появления **FastAPI**.
+
+Использование этого стека привело к созданию нескольких генераторов проектов. Я и некоторые другие команды до сих пор используем их:
+
+* https://github.com/tiangolo/full-stack
+* https://github.com/tiangolo/full-stack-flask-couchbase
+* https://github.com/tiangolo/full-stack-flask-couchdb
+
+Эти генераторы проектов также стали основой для [Генераторов проектов с **FastAPI**](project-generation.md){.internal-link target=_blank}.
+
+!!! info "Информация"
+ Как ни странно, но Flask-apispec тоже создан авторами Marshmallow.
+
+!!! check "Идея для **FastAPI**"
+ Схема OpenAPI должна создаваться автоматически и использовать тот же код, который осуществляет сериализацию и проверку данных.
+
+### NestJS (и Angular)
+
+Здесь даже не используется Python. NestJS - этот фреймворк написанный на JavaScript (TypeScript), основанный на NodeJS и вдохновлённый Angular.
+
+Он позволяет получить нечто похожее на то, что можно сделать с помощью Flask-apispec.
+
+В него встроена система внедрения зависимостей, ещё одна идея взятая от Angular.
+Однако требуется предварительная регистрация "внедрений" (как и во всех других известных мне системах внедрения зависимостей), что увеличивает количество и повторяемость кода.
+
+Так как параметры в нём описываются с помощью типов TypeScript (аналогично подсказкам типов в Python), поддержка редактора работает довольно хорошо.
+
+Но поскольку данные из TypeScript не сохраняются после компиляции в JavaScript, он не может полагаться на подсказки типов для определения проверки данных, сериализации и документации.
+Из-за этого и некоторых дизайнерских решений, для валидации, сериализации и автоматической генерации схем, приходится во многих местах добавлять декораторы.
+Таким образом, это становится довольно многословным.
+
+Кроме того, он не очень хорошо справляется с вложенными моделями.
+Если в запросе имеется объект JSON, внутренние поля которого, в свою очередь, являются вложенными объектами JSON, это не может быть должным образом задокументировано и проверено.
+
+!!! check "Идеи для **FastAPI** "
+ Нужно использовать подсказки типов, чтоб воспользоваться поддержкой редактора кода.
+
+ Нужна мощная система внедрения зависимостей. Необходим способ для уменьшения повторов кода.
+
+### Sanic
+
+Sanic был одним из первых чрезвычайно быстрых Python-фреймворков основанных на `asyncio`.
+Он был сделан очень похожим на Flask.
+
+!!! note "Технические детали"
+ В нём использован `uvloop` вместо стандартного цикла событий `asyncio`, что и сделало его таким быстрым.
+
+ Он явно вдохновил создателей Uvicorn и Starlette, которые в настоящее время быстрее Sanic в открытых бенчмарках.
+
+!!! check "Идеи для **FastAPI**"
+ Должна быть сумасшедшая производительность.
+
+ Для этого **FastAPI** основан на Starlette, самом быстром из доступных фреймворков (по замерам незаинтересованных лиц).
+
+### Falcon
+
+Falcon - ещё один высокопроизводительный Python-фреймворк.
+В нём минимум функций и он создан, чтоб быть основой для других фреймворков, например, Hug.
+
+Функции в нём получают два параметра - "запрос к серверу" и "ответ сервера".
+Затем Вы "читаете" часть запроса и "пишите" часть ответа.
+Из-за такой конструкции невозможно объявить параметры запроса и тела сообщения со стандартными подсказками типов Python в качестве параметров функции.
+
+Таким образом, и валидацию данных, и их сериализацию, и документацию нужно прописывать вручную.
+Либо эти функции должны быть встроены во фреймворк, сконструированный поверх Falcon, как в Hug.
+Такая же особенность присутствует и в других фреймворках, вдохновлённых идеей Falcon, использовать только один объект запроса и один объект ответа.
+
+!!! check "Идея для **FastAPI**"
+ Найдите способы добиться отличной производительности.
+
+ Объявлять параметры `ответа сервера` в функциях, как в Hug.
+
+ Хотя в FastAPI это необязательно и используется в основном для установки заголовков, куки и альтернативных кодов состояния.
+
+### Molten
+
+Molten мне попался на начальной стадии написания **FastAPI**. В нём были похожие идеи:
+
+* Использование подсказок типов.
+* Валидация и документация исходя из этих подсказок.
+* Система внедрения зависимостей.
+
+В нём не используются сторонние библиотеки (такие, как Pydantic) для валидации, сериализации и документации.
+Поэтому переиспользовать эти определения типов непросто.
+
+Также требуется более подробная конфигурация и используется стандарт WSGI, который не предназначен для использования с высокопроизводительными инструментами, такими как Uvicorn, Starlette и Sanic, в отличие от ASGI.
+
+Его система внедрения зависимостей требует предварительной регистрации, и зависимости определяются, как объявления типов.
+Из-за этого невозможно объявить более одного "компонента" (зависимости), который предоставляет определенный тип.
+
+Маршруты объявляются в единственном месте с использованием функций, объявленных в других местах (вместо использования декораторов, в которые могут быть обёрнуты функции, обрабатывающие конкретные ресурсы).
+Это больше похоже на Django, чем на Flask и Starlette.
+Он разделяет в коде вещи, которые довольно тесно связаны.
+
+!!! check "Идея для **FastAPI**"
+ Определить дополнительные проверки типов данных, используя значения атрибутов модели "по умолчанию".
+ Это улучшает помощь редактора и раньше это не было доступно в Pydantic.
+
+ Фактически это подтолкнуло на обновление Pydantic для поддержки одинакового стиля проверок (теперь этот функционал уже доступен в Pydantic).
+
+### Hug
+
+Hug был одним из первых фреймворков, реализовавших объявление параметров API с использованием подсказок типов Python.
+Эта отличная идея была использована и другими инструментами.
+
+При объявлении параметров вместо стандартных типов Python использовались собственные типы, но всё же это был огромный шаг вперед.
+
+Это также был один из первых фреймворков, генерировавших полную API-схему в формате JSON.
+
+Данная схема не придерживалась стандартов вроде OpenAPI и JSON Schema.
+Поэтому было бы непросто совместить её с другими инструментами, такими как Swagger UI.
+Но опять же, это была очень инновационная идея.
+
+Ещё у него есть интересная и необычная функция: используя один и тот же фреймворк можно создавать и API, и CLI.
+
+Поскольку он основан на WSGI, старом стандарте для синхронных веб-фреймворков, он не может работать с веб-сокетами и другими модными штуками, но всё равно обладает высокой производительностью.
+
+!!! info "Информация"
+ Hug создан Timothy Crosley, автором `isort`, отличного инструмента для автоматической сортировки импортов в Python-файлах.
+
+!!! check "Идеи для **FastAPI**"
+ Hug повлиял на создание некоторых частей APIStar и был одним из инструментов, которые я счел наиболее многообещающими, наряду с APIStar.
+
+ Hug натолкнул на мысли использовать в **FastAPI** подсказки типов Python для автоматического создания схемы, определяющей API и его параметры.
+
+ Hug вдохновил **FastAPI** объявить параметр `ответа` в функциях для установки заголовков и куки.
+
+### APIStar (<= 0.5)
+
+Непосредственно перед тем, как принять решение о создании **FastAPI**, я обнаружил **APIStar**.
+В нем было почти все, что я искал и у него был отличный дизайн.
+
+Это была одна из первых реализаций фреймворка, использующего подсказки типов для объявления параметров и запросов, которые я когда-либо видел (до NestJS и Molten).
+Я нашёл его примерно в то же время, что и Hug, но APIStar использовал стандарт OpenAPI.
+
+В нём были автоматические проверка и сериализация данных и генерация схемы OpenAPI основанные на подсказках типов в нескольких местах.
+
+При определении схемы тела сообщения не использовались подсказки типов, как в Pydantic, это больше похоже на Marshmallow, поэтому помощь редактора была недостаточно хорошей, но всё же APIStar был лучшим доступным вариантом.
+
+На тот момент у него были лучшие показатели производительности (проигрывающие только Starlette).
+
+Изначально у него не было автоматической документации API для веб-интерфейса, но я знал, что могу добавить к нему Swagger UI.
+
+В APIStar была система внедрения зависимостей, которая тоже требовала предварительную регистрацию компонентов, как и ранее описанные инструменты.
+Но, тем не менее, это была отличная штука.
+
+Я не смог использовать его в полноценном проекте, так как были проблемы со встраиванием функций безопасности в схему OpenAPI, из-за которых невозможно было встроить все функции, применяемые в генераторах проектов на основе Flask-apispec.
+Я добавил в свой список задач создание пул-реквеста, добавляющего эту функциональность.
+
+В дальнейшем фокус проекта сместился.
+
+Это больше не был API-фреймворк, так как автор сосредоточился на Starlette.
+
+Ныне APIStar - это набор инструментов для проверки спецификаций OpenAPI.
+
+!!! info "Информация"
+ APIStar был создан Tom Christie. Тот самый парень, который создал:
+
+ * Django REST Framework
+ * Starlette (на котором основан **FastAPI**)
+ * Uvicorn (используемый в Starlette и **FastAPI**)
+
+!!! check "Идеи для **FastAPI**"
+ Воплощение.
+
+ Мне казалось блестящей идеей объявлять множество функций (проверка данных, сериализация, документация) с помощью одних и тех же типов Python, которые при этом обеспечивают ещё и помощь редактора кода.
+
+ После долгих поисков среди похожих друг на друга фреймворков и сравнения их различий, APIStar стал самым лучшим выбором.
+
+ Но APIStar перестал быть фреймворком для создания веб-сервера, зато появился Starlette, новая и лучшая основа для построения подобных систем.
+ Это была последняя капля, сподвигнувшая на создание **FastAPI**.
+
+ Я считаю **FastAPI** "духовным преемником" APIStar, улучившим его возможности благодаря урокам, извлечённым из всех упомянутых выше инструментов.
+
+## Что используется в **FastAPI**
+
+### Pydantic
+
+Pydantic - это библиотека для валидации данных, сериализации и документирования (используя JSON Schema), основываясь на подсказках типов Python, что делает его чрезвычайно интуитивным.
+
+Его можно сравнить с Marshmallow, хотя в бенчмарках Pydantic быстрее, чем Marshmallow.
+И он основан на тех же подсказках типов, которые отлично поддерживаются редакторами кода.
+
+!!! check "**FastAPI** использует Pydantic"
+ Для проверки данных, сериализации данных и автоматической документации моделей (на основе JSON Schema).
+
+ Затем **FastAPI** берёт эти схемы JSON и помещает их в схему OpenAPI, не касаясь других вещей, которые он делает.
+
+### Starlette
+
+Starlette - это легковесный ASGI фреймворк/набор инструментов, который идеален для построения высокопроизводительных асинхронных сервисов.
+
+Starlette очень простой и интуитивный.
+Он разработан таким образом, чтобы быть легко расширяемым и иметь модульные компоненты.
+
+В нём есть:
+
+* Впечатляющая производительность.
+* Поддержка веб-сокетов.
+* Фоновые задачи.
+* Обработка событий при старте и финише приложения.
+* Тестовый клиент на основе HTTPX.
+* Поддержка CORS, сжатие GZip, статические файлы, потоковая передача данных.
+* Поддержка сессий и куки.
+* 100% покрытие тестами.
+* 100% аннотированный код.
+* Несколько жёстких зависимостей.
+
+В настоящее время Starlette показывает самую высокую скорость среди Python-фреймворков в тестовых замерах.
+Быстрее только Uvicorn, который является сервером, а не фреймворком.
+
+Starlette обеспечивает весь функционал микрофреймворка, но не предоставляет автоматическую валидацию данных, сериализацию и документацию.
+
+**FastAPI** добавляет эти функции используя подсказки типов Python и Pydantic.
+Ещё **FastAPI** добавляет систему внедрения зависимостей, утилиты безопасности, генерацию схемы OpenAPI и т.д.
+
+!!! note "Технические детали"
+ ASGI - это новый "стандарт" разработанный участниками команды Django.
+ Он пока что не является "стандартом в Python" (то есть принятым PEP), но процесс принятия запущен.
+
+ Тем не менее он уже используется в качестве "стандарта" несколькими инструментами.
+ Это значительно улучшает совместимость, поскольку Вы можете переключиться с Uvicorn на любой другой ASGI-сервер (например, Daphne или Hypercorn) или Вы можете добавить ASGI-совместимые инструменты, такие как `python-socketio`.
+
+!!! check "**FastAPI** использует Starlette"
+ В качестве ядра веб-сервиса для обработки запросов, добавив некоторые функции сверху.
+
+ Класс `FastAPI` наследуется напрямую от класса `Starlette`.
+
+ Таким образом, всё что Вы могли делать со Starlette, Вы можете делать с **FastAPI**, по сути это прокачанный Starlette.
+
+### Uvicorn
+
+Uvicorn - это молниеносный ASGI-сервер, построенный на uvloop и httptools.
+
+Uvicorn является сервером, а не фреймворком.
+Например, он не предоставляет инструментов для маршрутизации запросов по ресурсам.
+Для этого нужна надстройка, такая как Starlette (или **FastAPI**).
+
+Он рекомендуется в качестве сервера для Starlette и **FastAPI**.
+
+!!! check "**FastAPI** рекомендует его"
+ Как основной сервер для запуска приложения **FastAPI**.
+
+ Вы можете объединить его с Gunicorn, чтобы иметь асинхронный многопроцессный сервер.
+
+ Узнать больше деталей можно в разделе [Развёртывание](deployment/index.md){.internal-link target=_blank}.
+
+## Тестовые замеры и скорость
+
+Чтобы понять, сравнить и увидеть разницу между Uvicorn, Starlette и FastAPI, ознакомьтесь с разделом [Тестовые замеры](benchmarks.md){.internal-link target=_blank}.
diff --git a/docs/ru/docs/benchmarks.md b/docs/ru/docs/benchmarks.md
new file mode 100644
index 000000000..259dca8e6
--- /dev/null
+++ b/docs/ru/docs/benchmarks.md
@@ -0,0 +1,37 @@
+# Замеры производительности
+
+Независимые тесты производительности приложений от TechEmpower показывают, что **FastAPI** под управлением Uvicorn один из самых быстрых Python-фреймворков и уступает только 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.
+ * Зато он предоставляет Вам инструменты для создания простых веб-приложений с обработкой маршрутов URL и т.д.
+ * Starlette следует сравнивать с Sanic, Flask, Django и другими веб-фреймворками (или микрофреймворками).
+
+* **FastAPI**:
+ * Так же как Starlette использует Uvicorn и не может быть быстрее него, **FastAPI** использует Starlette, то есть он не может быть быстрее Starlette.
+ * FastAPI предоставляет больше возможностей поверх Starlette, которые наверняка Вам понадобятся при создании API, такие как проверка данных и сериализация. В довесок Вы ещё и получаете автоматическую документацию (автоматическая документация даже не увеличивает накладные расходы при работе приложения, так как она создается при запуске).
+ * Если Вы не используете FastAPI, а используете Starlette напрямую (или другой инструмент вроде Sanic, Flask, Responder и т.д.), Вам пришлось бы самостоятельно реализовать валидацию и сериализацию данных. То есть, в итоге, Ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях.
+ * Таким образом, используя FastAPI Вы потратите меньше времени на разработку, уменьшите количество ошибок, строк кода и, вероятно, получите ту же производительность (или лучше), как и если бы не использовали его (поскольку Вам пришлось бы реализовать все его возможности в своем коде).
+ * FastAPI должно сравнивать с фреймворками веб-приложений (или наборами инструментов), которые обеспечивают валидацию и сериализацию данных, а также предоставляют автоматическую документацию, такими как Flask-apispec, NestJS, Molten и им подобные.
diff --git a/docs/ru/docs/contributing.md b/docs/ru/docs/contributing.md
new file mode 100644
index 000000000..f61ef1cb6
--- /dev/null
+++ b/docs/ru/docs/contributing.md
@@ -0,0 +1,469 @@
+# Участие в разработке фреймворка
+
+Возможно, для начала Вам стоит ознакомиться с основными способами [помочь FastAPI или получить помощь](help-fastapi.md){.internal-link target=_blank}.
+
+## Разработка
+
+Если Вы уже склонировали репозиторий и знаете, что Вам нужно более глубокое погружение в код фреймворка, то здесь представлены некоторые инструкции по настройке виртуального окружения.
+
+### Виртуальное окружение с помощью `venv`
+
+Находясь в нужной директории, Вы можете создать виртуальное окружение при помощи Python модуля `venv`.
+
+
+
+```console
+$ python -m venv env
+```
+
+
+
+Эта команда создаст директорию `./env/` с бинарными (двоичными) файлами Python, а затем Вы сможете скачивать и устанавливать необходимые библиотеки в изолированное виртуальное окружение.
+
+### Активация виртуального окружения
+
+Активируйте виртуально окружение командой:
+
+=== "Linux, macOS"
+
+
+
+ ```console
+ $ source ./env/bin/activate
+ ```
+
+
+
+=== "Windows PowerShell"
+
+
+
+ ```console
+ $ .\env\Scripts\Activate.ps1
+ ```
+
+
+
+=== "Windows Bash"
+
+ Если Вы пользуетесь Bash для Windows (например: Git Bash):
+
+
+
+ ```console
+ $ source ./env/Scripts/activate
+ ```
+
+
+
+Проверьте, что всё сработало:
+
+=== "Linux, macOS, Windows Bash"
+
+
+
+ ```console
+ $ which pip
+
+ some/directory/fastapi/env/bin/pip
+ ```
+
+
+
+=== "Windows PowerShell"
+
+
+
+ ```console
+ $ Get-Command pip
+
+ some/directory/fastapi/env/bin/pip
+ ```
+
+
+
+Если в терминале появится ответ, что бинарник `pip` расположен по пути `.../env/bin/pip`, значит всё в порядке. 🎉
+
+Во избежание ошибок в дальнейших шагах, удостоверьтесь, что в Вашем виртуальном окружении установлена последняя версия `pip`:
+
+
+
+```console
+$ python -m pip install --upgrade pip
+
+---> 100%
+```
+
+
+
+!!! tip "Подсказка"
+ Каждый раз, перед установкой новой библиотеки в виртуальное окружение при помощи `pip`, не забудьте активировать это виртуальное окружение.
+
+ Это гарантирует, что если Вы используете библиотеку, установленную этим пакетом, то Вы используете библиотеку из Вашего локального окружения, а не любую другую, которая может быть установлена глобально.
+
+### pip
+
+После активации виртуального окружения, как было указано ранее, введите следующую команду:
+
+
+
+```console
+$ pip install -e ."[dev,doc,test]"
+
+---> 100%
+```
+
+
+
+Это установит все необходимые зависимости в локальное окружение для Вашего локального FastAPI.
+
+#### Использование локального FastAPI
+
+Если Вы создаёте Python файл, который импортирует и использует FastAPI,а затем запускаете его интерпретатором Python из Вашего локального окружения, то он будет использовать код из локального FastAPI.
+
+И, так как при вводе вышеупомянутой команды был указан флаг `-e`, если Вы измените код локального FastAPI, то при следующем запуске этого файла, он будет использовать свежую версию локального FastAPI, который Вы только что изменили.
+
+Таким образом, Вам не нужно "переустанавливать" Вашу локальную версию, чтобы протестировать каждое изменение.
+
+### Форматировние
+
+Скачанный репозиторий содержит скрипт, который может отформатировать и подчистить Ваш код:
+
+
+
+```console
+$ bash scripts/format.sh
+```
+
+
+
+Заодно он упорядочит Ваши импорты.
+
+Чтобы он сортировал их правильно, необходимо, чтобы FastAPI был установлен локально в Вашей среде, с помощью команды из раздела выше, использующей флаг `-e`.
+
+## Документация
+
+Прежде всего, убедитесь, что Вы настроили своё окружение, как описано выше, для установки всех зависимостей.
+
+Документация использует MkDocs.
+
+Также существуют дополнительные инструменты/скрипты для работы с переводами в `./scripts/docs.py`.
+
+!!! tip "Подсказка"
+
+ Нет необходимости заглядывать в `./scripts/docs.py`, просто используйте это в командной строке.
+
+Вся документация имеет формат Markdown и расположена в директории `./docs/en/`.
+
+Многие руководства содержат блоки кода.
+
+В большинстве случаев эти блоки кода представляют собой вполне законченные приложения, которые можно запускать как есть.
+
+На самом деле, эти блоки кода не написаны внутри Markdown, это Python файлы в директории `./docs_src/`.
+
+И эти Python файлы включаются/вводятся в документацию при создании сайта.
+
+### Тестирование документации
+
+
+Фактически, большинство тестов запускаются с примерами исходных файлов в документации.
+
+Это помогает убедиться, что:
+
+* Документация находится в актуальном состоянии.
+* Примеры из документации могут быть запущены как есть.
+* Большинство функций описаны в документации и покрыты тестами.
+
+Существует скрипт, который во время локальной разработки создаёт сайт и проверяет наличие любых изменений, перезагружая его в реальном времени:
+
+
+
+```console
+$ python ./scripts/docs.py live
+
+[INFO] Serving on http://127.0.0.1:8008
+[INFO] Start watching changes
+[INFO] Start detecting changes
+```
+
+
+
+Он запустит сайт документации по адресу: `http://127.0.0.1:8008`.
+
+
+Таким образом, Вы сможете редактировать файлы с документацией или кодом и наблюдать изменения вживую.
+
+#### Typer CLI (опционально)
+
+
+Приведенная ранее инструкция показала Вам, как запускать скрипт `./scripts/docs.py` непосредственно через интерпретатор `python` .
+
+Но также можно использовать Typer CLI, что позволит Вам воспользоваться автозаполнением команд в Вашем терминале.
+
+Если Вы установили Typer CLI, то для включения функции автозаполнения, введите эту команду:
+
+
+
+```console
+$ typer --install-completion
+
+zsh completion installed in /home/user/.bashrc.
+Completion will take effect once you restart the terminal.
+```
+
+
+
+### Приложения и документация одновременно
+
+Если Вы запускаете приложение, например так:
+
+
+
+```console
+$ uvicorn tutorial001:app --reload
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+По умолчанию Uvicorn будет использовать порт `8000` и не будет конфликтовать с сайтом документации, использующим порт `8008`.
+
+### Переводы на другие языки
+
+Помощь с переводами ценится КРАЙНЕ ВЫСОКО! И переводы не могут быть сделаны без помощи сообщества. 🌎 🚀
+
+Ниже приведены шаги, как помочь с переводами.
+
+#### Подсказки и инструкции
+
+* Проверьте существующие пул-реквесты для Вашего языка. Добавьте отзывы с просьбой внести изменения, если они необходимы, или одобрите их.
+
+!!! tip "Подсказка"
+ Вы можете добавлять комментарии с предложениями по изменению в существующие пул-реквесты.
+
+ Ознакомьтесь с документацией о добавлении отзыва к пул-реквесту, чтобы утвердить его или запросить изменения.
+
+* Проверьте проблемы и вопросы, чтобы узнать, есть ли кто-то, координирующий переводы для Вашего языка.
+
+* Добавляйте один пул-реквест для каждой отдельной переведённой страницы. Это значительно облегчит другим его просмотр.
+
+Для языков, которые я не знаю, прежде чем добавить перевод в основную ветку, я подожду пока несколько других участников сообщества проверят его.
+
+* Вы также можете проверить, есть ли переводы для Вашего языка и добавить к ним отзыв, который поможет мне убедиться в правильности перевода. Тогда я смогу объединить его с основной веткой.
+
+* Используйте те же самые примеры кода Python. Переводите только текст документации. Вам не нужно ничего менять, чтобы эти примеры работали.
+
+* Используйте те же самые изображения, имена файлов и ссылки. Вы не должны менять ничего для сохранения работоспособности.
+
+* Чтобы узнать 2-буквенный код языка, на который Вы хотите сделать перевод, Вы можете воспользоваться таблицей Список кодов языков ISO 639-1.
+
+#### Существующий язык
+
+Допустим, Вы хотите перевести страницу на язык, на котором уже есть какие-то переводы, например, на испанский.
+
+Кодом испанского языка является `es`. А значит директория для переводов на испанский язык: `docs/es/`.
+
+!!! tip "Подсказка"
+ Главный ("официальный") язык - английский, директория для него `docs/en/`.
+
+Вы можете запустить сервер документации на испанском:
+
+
+
+```console
+// Используйте команду "live" и передайте код языка в качестве аргумента командной строки
+$ python ./scripts/docs.py live es
+
+[INFO] Serving on http://127.0.0.1:8008
+[INFO] Start watching changes
+[INFO] Start detecting changes
+```
+
+
+
+Теперь Вы можете перейти по адресу: http://127.0.0.1:8008 и наблюдать вносимые Вами изменения вживую.
+
+
+Если Вы посмотрите на сайт документации FastAPI, то увидите, что все страницы есть на каждом языке. Но некоторые страницы не переведены и имеют уведомление об отсутствующем переводе.
+
+Но когда Вы запускаете сайт локально, Вы видите только те страницы, которые уже переведены.
+
+
+Предположим, что Вы хотите добавить перевод страницы [Основные свойства](features.md){.internal-link target=_blank}.
+
+* Скопируйте файл:
+
+```
+docs/en/docs/features.md
+```
+
+* Вставьте его точно в то же место, но в директорию языка, на который Вы хотите сделать перевод, например:
+
+```
+docs/es/docs/features.md
+```
+
+!!! tip "Подсказка"
+ Заметьте, что в пути файла мы изменили только код языка с `en` на `es`.
+
+* Теперь откройте файл конфигурации MkDocs для английского языка, расположенный тут:
+
+```
+docs/en/mkdocs.yml
+```
+
+* Найдите в файле конфигурации место, где расположена строка `docs/features.md`. Похожее на это:
+
+```YAML hl_lines="8"
+site_name: FastAPI
+# More stuff
+nav:
+- FastAPI: index.md
+- Languages:
+ - en: /
+ - es: /es/
+- features.md
+```
+
+* Откройте файл конфигурации MkDocs для языка, на который Вы переводите, например:
+
+```
+docs/es/mkdocs.yml
+```
+
+* Добавьте строку `docs/features.md` точно в то же место, как и в случае для английского, как-то так:
+
+```YAML hl_lines="8"
+site_name: FastAPI
+# More stuff
+nav:
+- FastAPI: index.md
+- Languages:
+ - en: /
+ - es: /es/
+- features.md
+```
+
+Убедитесь, что при наличии других записей, новая запись с Вашим переводом находится точно в том же порядке, что и в английской версии.
+
+Если Вы зайдёте в свой браузер, то увидите, что в документации стал отображаться Ваш новый раздел.🎉
+
+Теперь Вы можете переводить эту страницу и смотреть, как она выглядит при сохранении файла.
+
+#### Новый язык
+
+Допустим, Вы хотите добавить перевод для языка, на который пока что не переведена ни одна страница.
+
+Скажем, Вы решили сделать перевод для креольского языка, но его еще нет в документации.
+
+Перейдите в таблицу кодов языков по ссылке указанной выше, где найдёте, что кодом креольского языка является `ht`.
+
+Затем запустите скрипт, генерирующий директорию для переводов на новые языки:
+
+
+
+```console
+// Используйте команду new-lang и передайте код языка в качестве аргумента командной строки
+$ python ./scripts/docs.py new-lang ht
+
+Successfully initialized: docs/ht
+Updating ht
+Updating en
+```
+
+
+
+После чего Вы можете проверить в своем редакторе кода, что появился новый каталог `docs/ht/`.
+
+!!! tip "Подсказка"
+ Создайте первый пул-реквест, который будет содержать только пустую директорию для нового языка, прежде чем добавлять переводы.
+
+ Таким образом, другие участники могут переводить другие страницы, пока Вы работаете над одной. 🚀
+
+Начните перевод с главной страницы `docs/ht/index.md`.
+
+В дальнейшем можно действовать, как указано в предыдущих инструкциях для "существующего языка".
+
+##### Новый язык не поддерживается
+
+Если при запуске скрипта `./scripts/docs.py live` Вы получаете сообщение об ошибке, что язык не поддерживается, что-то вроде:
+
+```
+ raise TemplateNotFound(template)
+jinja2.exceptions.TemplateNotFound: partials/language/xx.html
+```
+
+Сие означает, что тема не поддерживает этот язык (в данном случае с поддельным 2-буквенным кодом `xx`).
+
+Но не стоит переживать. Вы можете установить языком темы английский, а затем перевести текст документации.
+
+Если возникла такая необходимость, отредактируйте `mkdocs.yml` для Вашего нового языка. Это будет выглядеть как-то так:
+
+```YAML hl_lines="5"
+site_name: FastAPI
+# More stuff
+theme:
+ # More stuff
+ language: xx
+```
+
+Измените `xx` (код Вашего языка) на `en` и перезапустите сервер.
+
+#### Предпросмотр результата
+
+Когда Вы запускаете скрипт `./scripts/docs.py` с командой `live`, то будут показаны файлы и переводы для указанного языка.
+
+Но когда Вы закончите, то можете посмотреть, как это будет выглядеть по-настоящему.
+
+Для этого сначала создайте всю документацию:
+
+
+
+```console
+// Используйте команду "build-all", это займёт немного времени
+$ python ./scripts/docs.py build-all
+
+Updating es
+Updating en
+Building docs for: en
+Building docs for: es
+Successfully built docs for: es
+Copying en index.md to README.md
+```
+
+
+
+Скрипт сгенерирует `./docs_build/` для каждого языка. Он добавит все файлы с отсутствующими переводами с пометкой о том, что "у этого файла еще нет перевода". Но Вам не нужно ничего делать с этим каталогом.
+
+Затем он создаст независимые сайты MkDocs для каждого языка, объединит их и сгенерирует конечный результат на `./site/`.
+
+После чего Вы сможете запустить сервер со всеми языками командой `serve`:
+
+
+
+```console
+// Используйте команду "serve" после того, как отработает команда "build-all"
+$ python ./scripts/docs.py serve
+
+Warning: this is a very simple server. For development, use mkdocs serve instead.
+This is here only to preview a site with translations already built.
+Make sure you run the build-all command first.
+Serving at: http://127.0.0.1:8008
+```
+
+
+
+## Тесты
+
+Также в репозитории есть скрипт, который Вы можете запустить локально, чтобы протестировать весь код и сгенерировать отчеты о покрытии тестами в HTML:
+
+
+
+```console
+$ bash scripts/test-cov-html.sh
+```
+
+
+
+Эта команда создаст директорию `./htmlcov/`, в которой будет файл `./htmlcov/index.html`. Открыв его в Вашем браузере, Вы можете в интерактивном режиме изучить, все ли части кода охвачены тестами.
diff --git a/docs/ru/docs/deployment/https.md b/docs/ru/docs/deployment/https.md
new file mode 100644
index 000000000..a53ab6927
--- /dev/null
+++ b/docs/ru/docs/deployment/https.md
@@ -0,0 +1,198 @@
+# Об HTTPS
+
+Обычно представляется, что HTTPS это некая опция, которая либо "включена", либо нет.
+
+Но всё несколько сложнее.
+
+!!! tip "Заметка"
+ Если Вы торопитесь или Вам не интересно, можете перейти на следующую страницу этого пошагового руководства по размещению приложений на серверах с использованием различных технологий.
+
+Чтобы **изучить основы HTTPS** для клиента, перейдите по ссылке https://howhttps.works/.
+
+Здесь же представлены некоторые концепции, которые **разработчик** должен иметь в виду при размышлениях об HTTPS:
+
+* Протокол HTTPS предполагает, что **серверу** нужно **располагать "сертификатами"** сгенерированными **третьей стороной**.
+ * На самом деле эти сертификаты **приобретены** у третьей стороны, а не "сгенерированы".
+* У сертификатов есть **срок годности**.
+ * Срок годности **истекает**.
+ * По истечении срока годности их нужно **обновить**, то есть **снова получить** у третьей стороны.
+* Шифрование соединения происходит **на уровне протокола TCP**.
+ * Протокол TCP находится на один уровень **ниже протокола HTTP**.
+ * Поэтому **проверка сертификатов и шифрование** происходит **до HTTP**.
+* **TCP не знает о "доменах"**, но знает об IP-адресах.
+ * Информация о **запрашиваемом домене** извлекается из запроса **на уровне HTTP**.
+* **Сертификаты HTTPS** "сертифицируют" **конкретный домен**, но проверка сертификатов и шифрование данных происходит на уровне протокола TCP, то есть **до того**, как станет известен домен-получатель данных.
+* **По умолчанию** это означает, что у Вас может быть **только один сертификат HTTPS на один IP-адрес**.
+ * Не важно, насколько большой у Вас сервер и насколько маленькие приложения на нём могут быть.
+ * Однако, у этой проблемы есть **решение**.
+* Существует **расширение** протокола **TLS** (который работает на уровне TCP, то есть до HTTP) называемое **SNI**.
+ * Расширение SNI позволяет одному серверу (с **одним IP-адресом**) иметь **несколько сертификатов HTTPS** и обслуживать **множество HTTPS-доменов/приложений**.
+ * Чтобы эта конструкция работала, **один** её компонент (программа) запущенный на сервере и слушающий **публичный IP-адрес**, должен иметь **все сертификаты HTTPS** для этого сервера.
+* **После** установления защищённого соединения, протоколом передачи данных **остаётся HTTP**.
+ * Но данные теперь **зашифрованы**, несмотря на то, что они передаются по **протоколу HTTP**.
+
+Обычной практикой является иметь **одну программу/HTTP-сервер** запущенную на сервере (машине, хосте и т.д.) и **ответственную за всю работу с HTTPS**:
+
+* получение **зашифрованных HTTPS-запросов**
+* отправка **расшифрованных HTTP запросов** в соответствующее HTTP-приложение, работающее на том же сервере (в нашем случае, это приложение **FastAPI**)
+* получние **HTTP-ответа** от приложения
+* **шифрование ответа** используя подходящий **сертификат HTTPS**
+* отправка зашифрованного **HTTPS-ответа клиенту**.
+Такой сервер часто называют **Прокси-сервер завершения работы TLS** или просто "прокси-сервер".
+
+Вот некоторые варианты, которые Вы можете использовать в качестве такого прокси-сервера:
+
+* Traefik (может обновлять сертификаты)
+* Caddy (может обновлять сертификаты)
+* Nginx
+* HAProxy
+
+## Let's Encrypt (центр сертификации)
+
+До появления Let's Encrypt **сертификаты HTTPS** приходилось покупать у третьих сторон.
+
+Процесс получения такого сертификата был трудоёмким, требовал предоставления подтверждающих документов и сертификаты стоили дорого.
+
+Но затем консорциумом Linux Foundation был создан проект **Let's Encrypt**.
+
+Он автоматически предоставляет **бесплатные сертификаты HTTPS**. Эти сертификаты используют все стандартные криптографические способы шифрования. Они имеют небольшой срок годности (около 3 месяцев), благодаря чему они даже **более безопасны**.
+
+При запросе на получение сертификата, он автоматически генерируется и домен проверяется на безопасность. Это позволяет обновлять сертификаты автоматически.
+
+Суть идеи в автоматическом получении и обновлении этих сертификатов, чтобы все могли пользоваться **безопасным HTTPS. Бесплатно. В любое время.**
+
+## HTTPS для разработчиков
+
+Ниже, шаг за шагом, с заострением внимания на идеях, важных для разработчика, описано, как может выглядеть HTTPS API.
+
+### Имя домена
+
+Чаще всего, всё начинается с **приобретения имени домена**. Затем нужно настроить DNS-сервер (вероятно у того же провайдера, который выдал Вам домен).
+
+Далее, возможно, Вы получаете "облачный" сервер (виртуальную машину) или что-то типа этого, у которого есть постоянный **публичный IP-адрес**.
+
+На DNS-сервере (серверах) Вам следует настроить соответствующую ресурсную запись ("`запись A`"), указав, что **Ваш домен** связан с публичным **IP-адресом Вашего сервера**.
+
+Обычно эту запись достаточно указать один раз, при первоначальной настройке всего сервера.
+
+!!! tip "Заметка"
+ Уровни протоколов, работающих с именами доменов, намного ниже HTTPS, но об этом следует упомянуть здесь, так как всё зависит от доменов и IP-адресов.
+
+### DNS
+
+Теперь давайте сфокусируемся на работе с HTTPS.
+
+Всё начинается с того, что браузер спрашивает у **DNS-серверов**, какой **IP-адрес связан с доменом**, для примера возьмём домен `someapp.example.com`.
+
+DNS-сервера присылают браузеру определённый **IP-адрес**, тот самый публичный IP-адрес Вашего сервера, который Вы указали в ресурсной "записи А" при настройке.
+
+
+
+### Рукопожатие TLS
+
+В дальнейшем браузер будет взаимодействовать с этим IP-адресом через **port 443** (общепринятый номер порта для HTTPS).
+
+Первым шагом будет установление соединения между клиентом (браузером) и сервером и выбор криптографического ключа (для шифрования).
+
+
+
+Эта часть клиент-серверного взаимодействия устанавливает TLS-соединение и называется **TLS-рукопожатием**.
+
+### TLS с расширением SNI
+
+На сервере **только один процесс** может прослушивать определённый **порт** определённого **IP-адреса**. На сервере могут быть и другие процессы, слушающие другие порты этого же IP-адреса, но никакой процесс не может быть привязан к уже занятой комбинации IP-адрес:порт. Эта комбинация называется "сокет".
+
+По умолчанию TLS (HTTPS) использует порт `443`. Потому этот же порт будем использовать и мы.
+
+И раз уж только один процесс может слушать этот порт, то это будет процесс **прокси-сервера завершения работы TLS**.
+
+Прокси-сервер завершения работы TLS будет иметь доступ к одному или нескольким **TLS-сертификатам** (сертификаты HTTPS).
+
+Используя **расширение SNI** упомянутое выше, прокси-сервер из имеющихся сертификатов TLS (HTTPS) выберет тот, который соответствует имени домена, указанному в запросе от клиента.
+
+То есть будет выбран сертификат для домена `someapp.example.com`.
+
+
+
+Клиент уже **доверяет** тому, кто выдал этот TLS-сертификат (в нашем случае - Let's Encrypt, но мы ещё обсудим это), потому может **проверить**, действителен ли полученный от сервера сертификат.
+
+Затем, используя этот сертификат, клиент и прокси-сервер **выбирают способ шифрования** данных для устанавливаемого **TCP-соединения**. На этом операция **TLS-рукопожатия** завершена.
+
+В дальнейшем клиент и сервер будут взаимодействовать по **зашифрованному TCP-соединению**, как предлагается в протоколе TLS. И на основе этого TCP-соедениния будет создано **HTTP-соединение**.
+
+Таким образом, **HTTPS** это тот же **HTTP**, но внутри **безопасного TLS-соединения** вместо чистого (незашифрованного) TCP-соединения.
+
+!!! tip "Заметка"
+ Обратите внимание, что шифрование происходит на **уровне TCP**, а не на более высоком уровне HTTP.
+
+### HTTPS-запрос
+
+Теперь, когда между клиентом и сервером (в нашем случае, браузером и прокси-сервером) создано **зашифрованное TCP-соединение**, они могут начать **обмен данными по протоколу HTTP**.
+
+Так клиент отправляет **HTTPS-запрос**. То есть обычный HTTP-запрос, но через зашифрованное TLS-содинение.
+
+
+
+### Расшифровка запроса
+
+Прокси-сервер, используя согласованный с клиентом ключ, расшифрует полученный **зашифрованный запрос** и передаст **обычный (незашифрованный) HTTP-запрос** процессу, запускающему приложение (например, процессу Uvicorn запускающему приложение FastAPI).
+
+
+
+### HTTP-ответ
+
+Приложение обработает запрос и вернёт **обычный (незашифрованный) HTTP-ответ** прокси-серверу.
+
+
+
+### HTTPS-ответ
+
+Пркоси-сервер **зашифрует ответ** используя ранее согласованный с клиентом способ шифрования (которые содержатся в сертификате для домена `someapp.example.com`) и отправит его браузеру.
+
+Наконец, браузер проверит ответ, в том числе, что тот зашифрован с нужным ключом, **расшифрует его** и обработает.
+
+
+
+Клиент (браузер) знает, что ответ пришёл от правильного сервера, так как использует методы шифрования, согласованные ими раннее через **HTTPS-сертификат**.
+
+### Множество приложений
+
+На одном и том же сервере (или серверах) можно разместить **множество приложений**, например, другие программы с API или базы данных.
+
+Напомню, что только один процесс (например, прокси-сервер) может прослушивать определённый порт определённого IP-адреса.
+Но другие процессы и приложения тоже могут работать на этом же сервере (серверах), если они не пытаются использовать уже занятую **комбинацию IP-адреса и порта** (сокет).
+
+
+
+Таким образом, сервер завершения TLS может обрабатывать HTTPS-запросы и использовать сертификаты для **множества доменов** или приложений и передавать запросы правильным адресатам (другим приложениям).
+
+### Обновление сертификата
+
+В недалёком будущем любой сертификат станет **просроченным** (примерно через три месяца после получения).
+
+Когда это произойдёт, можно запустить другую программу, которая подключится к Let's Encrypt и обновит сертификат(ы). Существуют прокси-серверы, которые могут сделать это действие самостоятельно.
+
+
+
+**TLS-сертификаты** не привязаны к IP-адресу, но **связаны с именем домена**.
+
+Так что при обновлении сертификатов программа должна **подтвердить** центру сертификации (Let's Encrypt), что обновление запросил **"владелец", который контролирует этот домен**.
+
+Есть несколько путей осуществления этого. Самые популярные из них:
+
+* **Изменение записей DNS**.
+ * Для такого варианта Ваша программа обновления должна уметь работать с API DNS-провайдера, обслуживающего Ваши DNS-записи. Не у всех провайдеров есть такой API, так что этот способ не всегда применим.
+* **Запуск в качестве программы-сервера** (как минимум, на время обновления сертификатов) на публичном IP-адресе домена.
+ * Как уже не раз упоминалось, только один процесс может прослушивать определённый порт определённого IP-адреса.
+ * Это одна из причин использования прокси-сервера ещё и в качестве программы обновления сертификатов.
+ * В случае, если обновлением сертификатов занимается другая программа, Вам понадобится остановить прокси-сервер, запустить программу обновления сертификатов на сокете, предназначенном для прокси-сервера, настроить прокси-сервер на работу с новыми сертификатами и перезапустить его. Эта схема далека от идеальной, так как Ваши приложения будут недоступны на время отключения прокси-сервера.
+
+Весь этот процесс обновления, одновременный с обслуживанием запросов, является одной из основных причин, по которой желательно иметь **отдельную систему для работы с HTTPS** в виде прокси-сервера завершения TLS, а не просто использовать сертификаты TLS непосредственно с сервером приложений (например, Uvicorn).
+
+## Резюме
+
+Наличие **HTTPS** очень важно и довольно **критично** в большинстве случаев. Однако, Вам, как разработчику, не нужно тратить много сил на это, достаточно **понимать эти концепции** и принципы их работы.
+
+Но узнав базовые основы **HTTPS** Вы можете легко совмещать разные инструменты, которые помогут Вам в дальнейшей разработке.
+
+В следующих главах я покажу Вам несколько примеров, как настраивать **HTTPS** для приложений **FastAPI**. 🔒
diff --git a/docs/ru/docs/deployment/manually.md b/docs/ru/docs/deployment/manually.md
new file mode 100644
index 000000000..1d00b3086
--- /dev/null
+++ b/docs/ru/docs/deployment/manually.md
@@ -0,0 +1,150 @@
+# Запуск сервера вручную - Uvicorn
+
+Для запуска приложения **FastAPI** на удалённой серверной машине Вам необходим программный сервер, поддерживающий протокол ASGI, такой как **Uvicorn**.
+
+Существует три наиболее распространённые альтернативы:
+
+* Uvicorn: высокопроизводительный ASGI сервер.
+* Hypercorn: ASGI сервер, помимо прочего поддерживающий HTTP/2 и Trio.
+* Daphne: ASGI сервер, созданный для Django Channels.
+
+## Сервер как машина и сервер как программа
+
+В этих терминах есть некоторые различия и Вам следует запомнить их. 💡
+
+Слово "**сервер**" чаще всего используется в двух контекстах:
+
+- удалённый или расположенный в "облаке" компьютер (физическая или виртуальная машина).
+- программа, запущенная на таком компьютере (например, Uvicorn).
+
+Просто запомните, если Вам встретился термин "сервер", то обычно он подразумевает что-то из этих двух смыслов.
+
+Когда имеют в виду именно удалённый компьютер, часто говорят просто **сервер**, но ещё его называют **машина**, **ВМ** (виртуальная машина), **нода**. Все эти термины обозначают одно и то же - удалённый компьютер, обычно под управлением Linux, на котором Вы запускаете программы.
+
+## Установка программного сервера
+
+Вы можете установить сервер, совместимый с протоколом ASGI, так:
+
+=== "Uvicorn"
+
+ * Uvicorn, молниесный ASGI сервер, основанный на библиотеках uvloop и httptools.
+
+
+
+ ```console
+ $ pip install "uvicorn[standard]"
+
+ ---> 100%
+ ```
+
+
+
+ !!! tip "Подсказка"
+ С опцией `standard`, Uvicorn будет установливаться и использоваться с некоторыми дополнительными рекомендованными зависимостями.
+
+ В них входит `uvloop`, высокопроизводительная замена `asyncio`, которая значительно ускоряет работу асинхронных программ.
+
+=== "Hypercorn"
+
+ * Hypercorn, ASGI сервер, поддерживающий протокол HTTP/2.
+
+
+
+ ```console
+ $ pip install hypercorn
+
+ ---> 100%
+ ```
+
+
+
+ ...или какой-либо другой ASGI сервер.
+
+## Запуск серверной программы
+
+Затем запустите Ваше приложение так же, как было указано в руководстве ранее, но без опции `--reload`:
+
+=== "Uvicorn"
+
+
+
+ ```console
+ $ uvicorn main:app --host 0.0.0.0 --port 80
+
+ INFO: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
+ ```
+
+
+
+=== "Hypercorn"
+
+
+
+ ```console
+ $ hypercorn main:app --bind 0.0.0.0:80
+
+ Running on 0.0.0.0:8080 over http (CTRL + C to quit)
+ ```
+
+
+
+!!! warning "Предупреждение"
+
+ Не забудьте удалить опцию `--reload`, если ранее пользовались ею.
+
+ Включение опции `--reload` требует дополнительных ресурсов, влияет на стабильность работы приложения и может повлечь прочие неприятности.
+
+ Она сильно помогает во время **разработки**, но **не следует** использовать её при **реальной работе** приложения.
+
+## Hypercorn с Trio
+
+Starlette и **FastAPI** основаны на AnyIO, которая делает их совместимыми как с asyncio - стандартной библиотекой Python, так и с Trio.
+
+
+Тем не менее Uvicorn совместим только с asyncio и обычно используется совместно с `uvloop`, высокопроизводительной заменой `asyncio`.
+
+Но если Вы хотите использовать **Trio** напрямую, то можете воспользоваться **Hypercorn**, так как они совместимы. ✨
+
+### Установка Hypercorn с Trio
+
+Для начала, Вам нужно установить Hypercorn с поддержкой Trio:
+
+
+
+```console
+$ pip install "hypercorn[trio]"
+---> 100%
+```
+
+
+
+### Запуск с Trio
+
+Далее запустите Hypercorn с опцией `--worker-class` и аргументом `trio`:
+
+
+
+```console
+$ hypercorn main:app --worker-class trio
+```
+
+
+
+Hypercorn, в свою очередь, запустит Ваше приложение использующее Trio.
+
+Таким образом, Вы сможете использовать Trio в своём приложении. Но лучше использовать AnyIO, для сохранения совместимости и с Trio, и с asyncio. 🎉
+
+## Концепции развёртывания
+
+В вышеприведённых примерах серверные программы (например Uvicorn) запускали только **один процесс**, принимающий входящие запросы с любого IP (на это указывал аргумент `0.0.0.0`) на определённый порт (в примерах мы указывали порт `80`).
+
+Это основная идея. Но возможно, Вы озаботитесь добавлением дополнительных возможностей, таких как:
+
+* Использование более безопасного протокола HTTPS
+* Настройки запуска приложения
+* Перезагрузка приложения
+* Запуск нескольких экземпляров приложения
+* Управление памятью
+* Использование перечисленных функций перед запуском приложения.
+
+Я поведаю Вам больше о каждой из этих концепций в следующих главах, с конкретными примерами стратегий работы с ними. 🚀
diff --git a/docs/ru/docs/fastapi-people.md b/docs/ru/docs/fastapi-people.md
new file mode 100644
index 000000000..64ae66a03
--- /dev/null
+++ b/docs/ru/docs/fastapi-people.md
@@ -0,0 +1,180 @@
+
+# Люди, поддерживающие FastAPI
+
+У FastAPI замечательное сообщество, которое доброжелательно к людям с любым уровнем знаний.
+
+## Создатель и хранитель
+
+Ку! 👋
+
+Это я:
+
+{% if people %}
+
+{% for user in people.maintainers %}
+
+
+{% endfor %}
+
+
+{% endif %}
+
+Я создал и продолжаю поддерживать **FastAPI**. Узнать обо мне больше можно тут [Помочь FastAPI - Получить помощь - Связаться с автором](help-fastapi.md#connect-with-the-author){.internal-link target=_blank}.
+
+... но на этой странице я хочу показать вам наше сообщество.
+
+---
+
+**FastAPI** получает огромную поддержку от своего сообщества. И я хочу отметить вклад его участников.
+
+Это люди, которые:
+
+* [Помогают другим с их проблемами (вопросами) на GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank}.
+* [Создают пул-реквесты](help-fastapi.md#create-a-pull-request){.internal-link target=_blank}.
+* Делают ревью пул-реквестов, [что особенно важно для переводов на другие языки](contributing.md#translations){.internal-link target=_blank}.
+
+Поаплодируем им! 👏 🙇
+
+## Самые активные участники за прошедший месяц
+
+Эти участники [оказали наибольшую помощь другим с решением их проблем (вопросов) на GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} в течение последнего месяца. ☕
+
+{% if people %}
+
+{% for user in people.last_month_active %}
+
+
+{% endfor %}
+
+
+{% endif %}
+
+## Эксперты
+
+Здесь представлены **Эксперты FastAPI**. 🤓
+
+Эти участники [оказали наибольшую помощь другим с решением их проблем (вопросов) на GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} за *всё время*.
+
+Оказывая помощь многим другим, они подтвердили свой уровень знаний. ✨
+
+{% if people %}
+
+{% for user in people.experts %}
+
+
+{% endfor %}
+
+
+{% endif %}
+
+## Рейтинг участников, внёсших вклад в код
+
+Здесь представлен **Рейтинг участников, внёсших вклад в код**. 👷
+
+Эти люди [сделали наибольшее количество пул-реквестов](help-fastapi.md#create-a-pull-request){.internal-link target=_blank}, *включённых в основной код*.
+
+Они сделали наибольший вклад в исходный код, документацию, переводы и т.п. 📦
+
+{% if people %}
+
+{% for user in people.top_contributors %}
+
+
+{% endfor %}
+
+
+{% endif %}
+
+На самом деле таких людей довольно много (более сотни), вы можете увидеть всех на этой странице FastAPI GitHub Contributors page. 👷
+
+## Рейтинг ревьюеров
+
+Здесь представлен **Рейтинг ревьюеров**. 🕵️
+
+### Проверки переводов на другие языки
+
+Я знаю не очень много языков (и не очень хорошо 😅).
+Итак, ревьюеры - это люди, которые могут [**подтвердить предложенный вами перевод** документации](contributing.md#translations){.internal-link target=_blank}. Без них не было бы документации на многих языках.
+
+---
+
+В **Рейтинге ревьюеров** 🕵️ представлены те, кто проверил наибольшее количество пул-реквестов других участников, обеспечивая качество кода, документации и, особенно, **переводов на другие языки**.
+
+{% if people %}
+
+{% for user in people.top_reviewers %}
+
+
+{% endfor %}
+
+
+{% endif %}
+
+## Спонсоры
+
+Здесь представлены **Спонсоры**. 😎
+
+Спонсоры поддерживают мою работу над **FastAPI** (и другими проектами) главным образом через GitHub Sponsors.
+
+{% if sponsors %}
+
+{% if sponsors.gold %}
+
+### Золотые спонсоры
+
+{% for sponsor in sponsors.gold -%}
+
+{% endfor %}
+{% endif %}
+
+{% if sponsors.silver %}
+
+### Серебрянные спонсоры
+
+{% for sponsor in sponsors.silver -%}
+
+{% endfor %}
+{% endif %}
+
+{% if sponsors.bronze %}
+
+### Бронзовые спонсоры
+
+{% for sponsor in sponsors.bronze -%}
+
+{% endfor %}
+{% endif %}
+
+{% endif %}
+
+### Индивидуальные спонсоры
+
+{% if github_sponsors %}
+{% for group in github_sponsors.sponsors %}
+
+
+
+{% for user in group %}
+{% if user.login not in sponsors_badge.logins %}
+
+
+
+{% endif %}
+{% endfor %}
+
+
+
+{% endfor %}
+{% endif %}
+
+## О данных - технические детали
+
+Основная цель этой страницы - подчеркнуть усилия сообщества по оказанию помощи другим.
+
+Особенно это касается усилий, которые обычно менее заметны и во многих случаях более трудоемки, таких как помощь другим в решении проблем и проверка пул-реквестов с переводами.
+
+Данные рейтинги подсчитываются каждый месяц, ознакомиться с тем, как это работает можно тут.
+
+Кроме того, я также подчеркиваю вклад спонсоров.
+
+И я оставляю за собой право обновлять алгоритмы подсчёта, виды рейтингов, пороговые значения и т.д. (так, на всякий случай 🤷).
diff --git a/docs/ru/docs/help-fastapi.md b/docs/ru/docs/help-fastapi.md
new file mode 100644
index 000000000..a69e37bd8
--- /dev/null
+++ b/docs/ru/docs/help-fastapi.md
@@ -0,0 +1,257 @@
+# Помочь FastAPI - Получить помощь
+
+Нравится ли Вам **FastAPI**?
+
+Хотели бы Вы помочь FastAPI, его пользователям и автору?
+
+Может быть у Вас возникли трудности с **FastAPI** и Вам нужна помощь?
+
+Есть несколько очень простых способов оказания помощи (иногда достаточно всего лишь одного или двух кликов).
+
+И также есть несколько способов получить помощь.
+
+## Подписаться на новостную рассылку
+
+Вы можете подписаться на редкую [новостную рассылку **FastAPI и его друзья**](/newsletter/){.internal-link target=_blank} и быть в курсе о:
+
+* Новостях о FastAPI и его друзьях 🚀
+* Руководствах 📝
+* Возможностях ✨
+* Исправлениях 🚨
+* Подсказках и хитростях ✅
+
+## Подписаться на FastAPI в Twitter
+
+Подписаться на @fastapi в **Twitter** для получения наисвежайших новостей о **FastAPI**. 🐦
+
+## Добавить **FastAPI** звезду на GitHub
+
+Вы можете добавить FastAPI "звезду" на GitHub (кликнуть на кнопку звезды в верхнем правом углу экрана): https://github.com/tiangolo/fastapi. ⭐️
+
+Чем больше звёзд, тем легче другим пользователям найти нас и увидеть, что проект уже стал полезным для многих.
+
+## Отслеживать свежие выпуски в репозитории на GitHub
+
+Вы можете "отслеживать" FastAPI на GitHub (кликните по кнопке "watch" наверху справа): https://github.com/tiangolo/fastapi. 👀
+
+Там же Вы можете указать в настройках - "Releases only".
+
+С такой настройкой Вы будете получать уведомления на вашу электронную почту каждый раз, когда появится новый релиз (новая версия) **FastAPI** с исправлениями ошибок и новыми возможностями.
+
+## Связаться с автором
+
+Можно связаться со мной (Себястьян Рамирез / `tiangolo`), автором FastAPI.
+
+Вы можете:
+
+* Подписаться на меня на **GitHub**.
+ * Посмотреть другие мои проекты с открытым кодом, которые могут быть полезны Вам.
+ * Подписавшись на меня Вы сможете получать уведомления, что я создал новый проект с открытым кодом,.
+* Подписаться на меня в **Twitter** или в Mastodon.
+ * Поделиться со мной, как Вы используете FastAPI (я обожаю читать про это).
+ * Получать уведомления, когда я делаю объявления и представляю новые инструменты.
+ * Вы также можете подписаться на @fastapi в Twitter (это отдельный аккаунт).
+* Подписаться на меня в **Linkedin**.
+ * Получать уведомления, когда я делаю объявления и представляю новые инструменты (правда чаще всего я использую Twitter 🤷♂).
+* Читать, что я пишу (или подписаться на меня) в **Dev.to** или в **Medium**.
+ * Читать другие идеи, статьи и читать об инструментах созданных мной.
+ * Подпишитесь на меня, чтобы прочитать, когда я опубликую что-нибудь новое.
+
+## Оставить сообщение в Twitter о **FastAPI**
+
+Оставьте сообщение в Twitter о **FastAPI** и позвольте мне и другим узнать - почему он Вам нравится. 🎉
+
+Я люблю узнавать о том, как **FastAPI** используется, что Вам понравилось в нём, в каких проектах/компаниях Вы используете его и т.п.
+
+## Оставить голос за FastAPI
+
+* Голосуйте за **FastAPI** в Slant.
+* Голосуйте за **FastAPI** в AlternativeTo.
+* Расскажите, как Вы используете **FastAPI** на StackShare.
+
+## Помочь другим с их проблемами на GitHub
+
+Вы можете посмотреть, какие проблемы испытывают другие люди и попытаться помочь им. Чаще всего это вопросы, на которые, весьма вероятно, Вы уже знаете ответ. 🤓
+
+Если Вы будете много помогать людям с решением их проблем, Вы можете стать официальным [Экспертом FastAPI](fastapi-people.md#experts){.internal-link target=_blank}. 🎉
+
+Только помните, самое важное при этом - доброта. Столкнувшись с проблемой, люди расстраиваются и часто задают вопросы не лучшим образом, но постарайтесь быть максимально доброжелательным. 🤗
+
+Идея сообщества **FastAPI** в том, чтобы быть добродушным и гостеприимными. Не допускайте издевательств или неуважительного поведения по отношению к другим. Мы должны заботиться друг о друге.
+
+---
+
+Как помочь другим с их проблемами:
+
+### Понять вопрос
+
+* Удостоверьтесь, что поняли **цель** и обстоятельства случая вопрошающего.
+
+* Затем проверьте, что вопрос (в подавляющем большинстве - это вопросы) Вам **ясен**.
+
+* Во многих случаях вопрос касается решения, которое пользователь придумал сам, но может быть и решение **получше**. Если Вы поймёте проблему и обстоятельства случая, то сможете предложить **альтернативное решение**.
+
+* Ежели вопрос Вам непонятен, запросите больше **деталей**.
+
+### Воспроизвести проблему
+
+В большинстве случаев есть что-то связанное с **исходным кодом** вопрошающего.
+
+И во многих случаях будет предоставлен только фрагмент этого кода, которого недостаточно для **воспроизведения проблемы**.
+
+* Попросите предоставить минимальный воспроизводимый пример, который можно **скопировать** и запустить локально дабы увидеть такую же ошибку, или поведение, или лучше понять обстоятельства случая.
+
+* Если на Вас нахлынуло великодушие, то можете попытаться **создать похожий пример** самостоятельно, основываясь только на описании проблемы. Но имейте в виду, что это может занять много времени и, возможно, стоит сначала позадавать вопросы для прояснения проблемы.
+
+### Предложить решение
+
+* После того как Вы поняли вопрос, Вы можете дать **ответ**.
+
+* Следует понять **основную проблему и обстоятельства случая**, потому что может быть решение лучше, чем то, которое пытались реализовать.
+
+### Попросить закрыть проблему
+
+Если Вам ответили, высоки шансы, что Вам удалось решить проблему, поздравляю, **Вы - герой**! 🦸
+
+* В таком случае, если вопрос решён, попросите **закрыть проблему**.
+
+## Отслеживать репозиторий на GitHub
+
+Вы можете "отслеживать" FastAPI на GitHub (кликните по кнопке "watch" наверху справа): https://github.com/tiangolo/fastapi. 👀
+
+Если Вы выберете "Watching" вместо "Releases only", то будете получать уведомления когда кто-либо попросит о помощи с решением его проблемы.
+
+Тогда Вы можете попробовать решить эту проблему.
+
+## Запросить помощь с решением проблемы
+
+Вы можете создать новый запрос с просьбой о помощи в репозитории на GitHub, например:
+
+* Задать **вопрос** или попросить помощи в решении **проблемы**.
+* Предложить новое **улучшение**.
+
+**Заметка**: Если Вы создаёте подобные запросы, то я попрошу Вас также оказывать аналогичную помощь другим. 😉
+
+## Проверять пул-реквесты
+
+Вы можете помочь мне проверять пул-реквесты других участников.
+
+И повторюсь, постарайтесь быть доброжелательным. 🤗
+
+---
+
+О том, что нужно иметь в виду при проверке пул-реквестов:
+
+### Понять проблему
+
+* Во-первых, убедитесь, что **поняли проблему**, которую пул-реквест пытается решить. Для этого может потребоваться продолжительное обсуждение.
+
+* Также есть вероятность, что пул-реквест не актуален, так как проблему можно решить **другим путём**. В таком случае Вы можете указать на этот факт.
+
+### Не переживайте о стиле
+
+* Не стоит слишком беспокоиться о таких вещах, как стиль сообщений в коммитах или количество коммитов. При слиянии пул-реквеста с основной веткой, я буду сжимать и настраивать всё вручную.
+
+* Также не беспокойтесь о правилах стиля, для проверки сего есть автоматизированные инструменты.
+
+И если всё же потребуется какой-то другой стиль, я попрошу Вас об этом напрямую или добавлю сам коммиты с необходимыми изменениями.
+
+### Проверить код
+
+* Проверьте и прочитайте код, посмотрите, какой он имеет смысл, **запустите его локально** и посмотрите, действительно ли он решает поставленную задачу.
+
+* Затем, используя **комментарий**, сообщите, что Вы сделали проверку, тогда я буду знать, что Вы действительно проверили код.
+
+!!! Информация
+ К сожалению, я не могу так просто доверять пул-реквестам, у которых уже есть несколько одобрений.
+
+ Бывали случаи, что пул-реквесты имели 3, 5 или больше одобрений, вероятно из-за привлекательного описания, но когда я проверял эти пул-реквесты, они оказывались сломаны, содержали ошибки или вовсе не решали проблему, которую, как они утверждали, должны были решить. 😅
+
+ Потому это действительно важно - проверять и запускать код, и комментарием уведомлять меня, что Вы проделали эти действия. 🤓
+
+* Если Вы считаете, что пул-реквест можно упростить, то можете попросить об этом, но не нужно быть слишком придирчивым, может быть много субъективных точек зрения (и у меня тоже будет своя 🙈), поэтому будет лучше, если Вы сосредоточитесь на фундаментальных вещах.
+
+### Тестировать
+
+* Помогите мне проверить, что у пул-реквеста есть **тесты**.
+
+* Проверьте, что тесты **падали** до пул-реквеста. 🚨
+
+* Затем проверьте, что тесты **не валятся** после пул-реквеста. ✅
+
+* Многие пул-реквесты не имеют тестов, Вы можете **напомнить** о необходимости добавления тестов или даже **предложить** какие-либо свои тесты. Это одна из тех вещей, которые отнимают много времени и Вы можете помочь с этим.
+
+* Затем добавьте комментарий, что Вы испробовали в ходе проверки. Таким образом я буду знать, как Вы произвели проверку. 🤓
+
+## Создать пул-реквест
+
+Вы можете [сделать вклад](contributing.md){.internal-link target=_blank} в код фреймворка используя пул-реквесты, например:
+
+* Исправить опечатку, которую Вы нашли в документации.
+* Поделиться статьёй, видео или подкастом о FastAPI, которые Вы создали или нашли изменив этот файл.
+ * Убедитесь, что Вы добавили свою ссылку в начало соответствующего раздела.
+* Помочь с [переводом документации](contributing.md#translations){.internal-link target=_blank} на Ваш язык.
+ * Вы также можете проверять переводы сделанные другими.
+* Предложить новые разделы документации.
+* Исправить существующуе проблемы/баги.
+ * Убедитесь, что добавили тесты.
+* Добавить новую возможность.
+ * Убедитесь, что добавили тесты.
+ * Убедитесь, что добавили документацию, если она необходима.
+
+## Помочь поддерживать FastAPI
+
+Помогите мне поддерживать **FastAPI**! 🤓
+
+Предстоит ещё много работы и, по большей части, **ВЫ** можете её сделать.
+
+Основные задачи, которые Вы можете выполнить прямо сейчас:
+
+* [Помочь другим с их проблемами на GitHub](#help-others-with-issues-in-github){.internal-link target=_blank} (смотрите вышестоящую секцию).
+* [Проверить пул-реквесты](#review-pull-requests){.internal-link target=_blank} (смотрите вышестоящую секцию).
+
+Эти две задачи **отнимают больше всего времени**. Это основная работа по поддержке FastAPI.
+
+Если Вы можете помочь мне с этим, **Вы помогаете поддерживать FastAPI** и следить за тем, чтобы он продолжал **развиваться быстрее и лучше**. 🚀
+
+## Подключиться к чату
+
+Подключайтесь к 👥 чату в Discord 👥 и общайтесь с другими участниками сообщества FastAPI.
+
+!!! Подсказка
+ Вопросы по проблемам с фреймворком лучше задавать в GitHub issues, так больше шансов, что Вы получите помощь от [Экспертов FastAPI](fastapi-people.md#experts){.internal-link target=_blank}.
+
+ Используйте этот чат только для бесед на отвлечённые темы.
+
+Существует также чат в Gitter, но поскольку в нем нет каналов и расширенных функций, общение в нём сложнее, потому рекомендуемой системой является Discord.
+
+### Не использовать чаты для вопросов
+
+Имейте в виду, что чаты позволяют больше "свободного общения", потому там легко задавать вопросы, которые слишком общие и на которые труднее ответить, так что Вы можете не получить нужные Вам ответы.
+
+В разделе "проблемы" на GitHub, есть шаблон, который поможет Вам написать вопрос правильно, чтобы Вам было легче получить хороший ответ или даже решить проблему самостоятельно, прежде чем Вы зададите вопрос. В GitHub я могу быть уверен, что всегда отвечаю на всё, даже если это займет какое-то время. И я не могу сделать то же самое в чатах. 😅
+
+Кроме того, общение в чатах не так легкодоступно для поиска, как в GitHub, потому вопросы и ответы могут потеряться среди другого общения. И только проблемы решаемые на GitHub учитываются в получении лычки [Эксперт FastAPI](fastapi-people.md#experts){.internal-link target=_blank}, так что весьма вероятно, что Вы получите больше внимания на GitHub.
+
+С другой стороны, в чатах тысячи пользователей, а значит есть большие шансы в любое время найти там кого-то, с кем можно поговорить. 😄
+
+## Спонсировать автора
+
+Вы также можете оказать мне финансовую поддержку посредством спонсорства через GitHub.
+
+Там можно просто купить мне кофе ☕️ в знак благодарности. 😄
+
+А ещё Вы можете стать Серебряным или Золотым спонсором для FastAPI. 🏅🎉
+
+## Спонсировать инструменты, на которых зиждется мощь FastAPI
+
+Как Вы могли заметить в документации, FastAPI опирается на плечи титанов: Starlette и Pydantic.
+
+Им тоже можно оказать спонсорскую поддержку:
+
+* Samuel Colvin (Pydantic)
+* Encode (Starlette, Uvicorn)
+
+---
+
+Благодарствую! 🚀
diff --git a/docs/ru/docs/history-design-future.md b/docs/ru/docs/history-design-future.md
new file mode 100644
index 000000000..2a5e428b1
--- /dev/null
+++ b/docs/ru/docs/history-design-future.md
@@ -0,0 +1,77 @@
+# История создания и дальнейшее развитие
+
+Однажды, один из пользователей **FastAPI** задал вопрос:
+
+> Какова история этого проекта? Создаётся впечатление, что он явился из ниоткуда и завоевал мир за несколько недель [...]
+
+Что ж, вот небольшая часть истории проекта.
+
+## Альтернативы
+
+В течение нескольких лет я, возглавляя различные команды разработчиков, создавал довольно сложные API для машинного обучения, распределённых систем, асинхронных задач, баз данных NoSQL и т.д.
+
+В рамках работы над этими проектами я исследовал, проверял и использовал многие фреймворки.
+
+Во многом история **FastAPI** - история его предшественников.
+
+Как написано в разделе [Альтернативы](alternatives.md){.internal-link target=_blank}:
+
+
+
+**FastAPI** не существовал бы, если б не было более ранних работ других людей.
+
+Они создали большое количество инструментов, которые и вдохновили меня на создание **FastAPI**.
+
+Я всячески избегал создания нового фреймворка в течение нескольких лет. Сначала я пытался собрать все нужные возможности, которые ныне есть в **FastAPI**, используя множество различных фреймворков, плагинов и инструментов.
+
+Но в какой-то момент не осталось другого выбора, кроме как создать что-то, что предоставляло бы все эти возможности сразу. Взять самые лучшие идеи из предыдущих инструментов и, используя введённые в Python подсказки типов (которых не было до версии 3.6), объединить их.
+
+
+
+## Исследования
+
+Благодаря опыту использования существующих альтернатив, мы с коллегами изучили их основные идеи и скомбинировали собранные знания наилучшим образом.
+
+Например, стало ясно, что необходимо брать за основу стандартные подсказки типов Python, а самым лучшим подходом является использование уже существующих стандартов.
+
+Итак, прежде чем приступить к написанию **FastAPI**, я потратил несколько месяцев на изучение OpenAPI, JSON Schema, OAuth2, и т.п. для понимания их взаимосвязей, совпадений и различий.
+
+## Дизайн
+
+Затем я потратил некоторое время на придумывание "API" разработчика, который я хотел иметь как пользователь (как разработчик, использующий FastAPI).
+
+Я проверил несколько идей на самых популярных редакторах кода среди Python-разработчиков: PyCharm, VS Code, Jedi.
+
+Данные по редакторам я взял из опроса Python-разработчиков, который охватываает около 80% пользователей.
+
+Это означает, что **FastAPI** был специально проверен на редакторах, используемых 80% Python-разработчиками. И поскольку большинство других редакторов, как правило, работают аналогичным образом, все его преимущества должны работать практически для всех редакторов.
+
+Таким образом, я смог найти наилучшие способы сократить дублирование кода, обеспечить повсеместное автодополнение, проверку типов и ошибок и т.д.
+
+И все это, чтобы все пользователи могли получать наилучший опыт разработки.
+
+## Зависимости
+
+Протестировав несколько вариантов, я решил, что в качестве основы буду использовать **Pydantic** и его преимущества.
+
+По моим предложениям был изменён код этого фреймворка, чтобы сделать его полностью совместимым с JSON Schema, поддержать различные способы определения ограничений и улучшить помощь редакторов (проверки типов, автозаполнение).
+
+В то же время, я принимал участие в разработке **Starlette**, ещё один из основных компонентов FastAPI.
+
+## Разработка
+
+К тому времени, когда я начал создавать **FastAPI**, большинство необходимых деталей уже существовало, дизайн был определён, зависимости и прочие инструменты были готовы, а знания о стандартах и спецификациях были четкими и свежими.
+
+## Будущее
+
+Сейчас уже ясно, что **FastAPI** со своими идеями стал полезен многим людям.
+
+При сравнении с альтернативами, выбор падает на него, поскольку он лучше подходит для множества вариантов использования.
+
+Многие разработчики и команды уже используют **FastAPI** в своих проектах (включая меня и мою команду).
+
+Но, тем не менее, грядёт добавление ещё многих улучшений и возможностей.
+
+У **FastAPI** великое будущее.
+
+И [ваш вклад в это](help-fastapi.md){.internal-link target=_blank} - очень ценнен.
diff --git a/docs/ru/docs/project-generation.md b/docs/ru/docs/project-generation.md
new file mode 100644
index 000000000..76253d6f2
--- /dev/null
+++ b/docs/ru/docs/project-generation.md
@@ -0,0 +1,84 @@
+# Генераторы проектов - Шаблоны
+
+Чтобы начать работу быстрее, Вы можете использовать "генераторы проектов", в которые включены множество начальных настроек для функций безопасности, баз данных и некоторые эндпоинты API.
+
+В генераторе проектов всегда будут предустановлены какие-то настройки, которые Вам следует обновить и подогнать под свои нужды, но это может быть хорошей отправной точкой для Вашего проекта.
+
+## Full Stack FastAPI PostgreSQL
+
+GitHub: https://github.com/tiangolo/full-stack-fastapi-postgresql
+
+### Full Stack FastAPI PostgreSQL - Особенности
+
+* Полностью интегрирован с **Docker** (основан на Docker).
+* Развёртывается в режиме Docker Swarm.
+* Интегрирован с **Docker Compose** и оптимизирован для локальной разработки.
+* **Готовый к реальной работе** веб-сервер Python использующий Uvicorn и Gunicorn.
+* Бэкенд построен на фреймворке **FastAPI**:
+ * **Быстрый**: Высокопроизводительный, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic).
+ * **Интуитивно понятный**: Отличная поддержка редактора. Автодополнение кода везде. Меньше времени на отладку.
+ * **Простой**: Разработан так, чтоб быть простым в использовании и изучении. Меньше времени на чтение документации.
+ * **Лаконичный**: Минимизировано повторение кода. Каждый объявленный параметр определяет несколько функций.
+ * **Надёжный**: Получите готовый к работе код. С автоматической интерактивной документацией.
+ * **Стандартизированный**: Основан на открытых стандартах API (OpenAPI и JSON Schema) и полностью совместим с ними.
+ * **Множество других возможностей** включая автоматическую проверку и сериализацию данных, интерактивную документацию, аутентификацию с помощью OAuth2 JWT-токенов и т.д.
+* **Безопасное хранение паролей**, которые хэшируются по умолчанию.
+* Аутентификация посредством **JWT-токенов**.
+* Модели **SQLAlchemy** (независящие от расширений Flask, а значит могут быть непосредственно использованы процессами Celery).
+* Базовая модель пользователя (измените или удалите её по необходимости).
+* **Alembic** для организации миграций.
+* **CORS** (Совместное использование ресурсов из разных источников).
+* **Celery**, процессы которого могут выборочно импортировать и использовать модели и код из остальной части бэкенда.
+* Тесты, на основе **Pytest**, интегрированные в Docker, чтобы Вы могли полностью проверить Ваше API, независимо от базы данных. Так как тесты запускаются в Docker, для них может создаваться новое хранилище данных каждый раз (Вы можете, по своему желанию, использовать ElasticSearch, MongoDB, CouchDB или другую СУБД, только лишь для проверки - будет ли Ваше API работать с этим хранилищем).
+* Простая интеграция Python с **Jupyter Kernels** для разработки удалённо или в Docker с расширениями похожими на Atom Hydrogen или Visual Studio Code Jupyter.
+* Фронтенд построен на фреймворке **Vue**:
+ * Сгенерирован с помощью Vue CLI.
+ * Поддерживает **аутентификацию с помощью JWT-токенов**.
+ * Страница логина.
+ * Перенаправление на страницу главной панели мониторинга после логина.
+ * Главная страница мониторинга с возможностью создания и изменения пользователей.
+ * Пользователь может изменять свои данные.
+ * **Vuex**.
+ * **Vue-router**.
+ * **Vuetify** для конструирования красивых компонентов страниц.
+ * **TypeScript**.
+ * Сервер Docker основан на **Nginx** (настроен для удобной работы с Vue-router).
+ * Многоступенчатая сборка Docker, то есть Вам не нужно сохранять или коммитить скомпилированный код.
+ * Тесты фронтенда запускаются во время сборки (можно отключить).
+ * Сделан настолько модульно, насколько возможно, поэтому работает "из коробки", но Вы можете повторно сгенерировать фронтенд с помощью Vue CLI или создать то, что Вам нужно и повторно использовать то, что захотите.
+* **PGAdmin** для СУБД PostgreSQL, которые легко можно заменить на PHPMyAdmin и MySQL.
+* **Flower** для отслеживания работы Celery.
+* Балансировка нагрузки между фронтендом и бэкендом с помощью **Traefik**, а значит, Вы можете расположить их на одном домене, разделив url-пути, так как они обслуживаются разными контейнерами.
+* Интеграция с Traefik включает автоматическую генерацию сертификатов Let's Encrypt для поддержки протокола **HTTPS**.
+* GitLab **CI** (непрерывная интеграция), которая включает тестирование фронтенда и бэкенда.
+
+## Full Stack FastAPI Couchbase
+
+GitHub: https://github.com/tiangolo/full-stack-fastapi-couchbase
+
+⚠️ **ПРЕДУПРЕЖДЕНИЕ** ⚠️
+
+Если Вы начинаете новый проект, ознакомьтесь с представленными здесь альтернативами.
+
+Например, генератор проектов Full Stack FastAPI PostgreSQL может быть более подходящей альтернативой, так как он активно поддерживается и используется. И он включает в себя все новые возможности и улучшения.
+
+Но никто не запрещает Вам использовать генератор с СУБД Couchbase, возможно, он всё ещё работает нормально. Или у Вас уже есть проект, созданный с помощью этого генератора ранее, и Вы, вероятно, уже обновили его в соответствии со своими потребностями.
+
+Вы можете прочитать о нём больше в документации соответствующего репозитория.
+
+## Full Stack FastAPI MongoDB
+
+...может быть когда-нибудь появится, в зависимости от наличия у меня свободного времени и прочих факторов. 😅 🎉
+
+## Модели машинного обучения на основе spaCy и FastAPI
+
+GitHub: https://github.com/microsoft/cookiecutter-spacy-fastapi
+
+### Модели машинного обучения на основе spaCy и FastAPI - Особенности
+
+* Интеграция с моделями **spaCy** NER.
+* Встроенный формат запросов к **когнитивному поиску Azure**.
+* **Готовый к реальной работе** веб-сервер Python использующий Uvicorn и Gunicorn.
+* Встроенное развёртывание на основе **Azure DevOps** Kubernetes (AKS) CI/CD.
+* **Многоязычность**. Лёгкий выбор одного из встроенных в spaCy языков во время настройки проекта.
+* **Легко подключить** модели из других фреймворков (Pytorch, Tensorflow) не ограничиваясь spaCy.
diff --git a/docs/ru/docs/tutorial/background-tasks.md b/docs/ru/docs/tutorial/background-tasks.md
index e608f6c8f..81efda786 100644
--- a/docs/ru/docs/tutorial/background-tasks.md
+++ b/docs/ru/docs/tutorial/background-tasks.md
@@ -57,16 +57,16 @@
**FastAPI** знает, что нужно сделать в каждом случае и как переиспользовать тот же объект `BackgroundTasks`, так чтобы все фоновые задачи собрались и запустились вместе в фоне:
-=== "Python 3.6 и выше"
+=== "Python 3.10+"
- ```Python hl_lines="13 15 22 25"
- {!> ../../../docs_src/background_tasks/tutorial002.py!}
+ ```Python hl_lines="11 13 20 23"
+ {!> ../../../docs_src/background_tasks/tutorial002_py310.py!}
```
-=== "Python 3.10 и выше"
+=== "Python 3.6+"
- ```Python hl_lines="11 13 20 23"
- {!> ../../../docs_src/background_tasks/tutorial002_py310.py!}
+ ```Python hl_lines="13 15 22 25"
+ {!> ../../../docs_src/background_tasks/tutorial002.py!}
```
В этом примере сообщения будут записаны в `log.txt` *после* того, как ответ сервера был отправлен.
diff --git a/docs/ru/docs/tutorial/body-fields.md b/docs/ru/docs/tutorial/body-fields.md
new file mode 100644
index 000000000..674b8bde4
--- /dev/null
+++ b/docs/ru/docs/tutorial/body-fields.md
@@ -0,0 +1,69 @@
+# Body - Поля
+
+Таким же способом, как вы объявляете дополнительную валидацию и метаданные в параметрах *функции обработки пути* с помощью функций `Query`, `Path` и `Body`, вы можете объявлять валидацию и метаданные внутри Pydantic моделей, используя функцию `Field` из Pydantic.
+
+## Импорт `Field`
+
+Сначала вы должны импортировать его:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="2"
+ {!> ../../../docs_src/body_fields/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="4"
+ {!> ../../../docs_src/body_fields/tutorial001.py!}
+ ```
+
+!!! warning "Внимание"
+ Обратите внимание, что функция `Field` импортируется непосредственно из `pydantic`, а не из `fastapi`, как все остальные функции (`Query`, `Path`, `Body` и т.д.).
+
+## Объявление атрибутов модели
+
+Вы можете использовать функцию `Field` с атрибутами модели:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="9-12"
+ {!> ../../../docs_src/body_fields/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="11-14"
+ {!> ../../../docs_src/body_fields/tutorial001.py!}
+ ```
+
+Функция `Field` работает так же, как `Query`, `Path` и `Body`, у ее такие же параметры и т.д.
+
+!!! note "Технические детали"
+ На самом деле, `Query`, `Path` и другие функции, которые вы увидите в дальнейшем, создают объекты подклассов общего класса `Param`, который сам по себе является подклассом `FieldInfo` из Pydantic.
+
+ И `Field` (из Pydantic), и `Body`, оба возвращают объекты подкласса `FieldInfo`.
+
+ У класса `Body` есть и другие подклассы, с которыми вы ознакомитесь позже.
+
+ Помните, что когда вы импортируете `Query`, `Path` и другое из `fastapi`, это фактически функции, которые возвращают специальные классы.
+
+!!! tip "Подсказка"
+ Обратите внимание, что каждый атрибут модели с типом, значением по умолчанию и `Field` имеет ту же структуру, что и параметр *функции обработки пути* с `Field` вместо `Path`, `Query` и `Body`.
+
+## Добавление дополнительной информации
+
+Вы можете объявлять дополнительную информацию в `Field`, `Query`, `Body` и т.п. Она будет включена в сгенерированную JSON схему.
+
+Вы узнаете больше о добавлении дополнительной информации позже в документации, когда будете изучать, как задавать примеры принимаемых данных.
+
+
+!!! warning "Внимание"
+ Дополнительные ключи, переданные в функцию `Field`, также будут присутствовать в сгенерированной OpenAPI схеме вашего приложения.
+ Поскольку эти ключи не являются обязательной частью спецификации OpenAPI, некоторые инструменты OpenAPI, например, [валидатор OpenAPI](https://validator.swagger.io/), могут не работать с вашей сгенерированной схемой.
+
+## Резюме
+
+Вы можете использовать функцию `Field` из Pydantic, чтобы задавать дополнительную валидацию и метаданные для атрибутов модели.
+
+Вы также можете использовать дополнительные ключевые аргументы, чтобы добавить метаданные JSON схемы.
diff --git a/docs/ru/docs/tutorial/cookie-params.md b/docs/ru/docs/tutorial/cookie-params.md
new file mode 100644
index 000000000..a6f2caa26
--- /dev/null
+++ b/docs/ru/docs/tutorial/cookie-params.md
@@ -0,0 +1,49 @@
+# Параметры Cookie
+
+Вы можете задать параметры Cookie таким же способом, как `Query` и `Path` параметры.
+
+## Импорт `Cookie`
+
+Сначала импортируйте `Cookie`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/cookie_params/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/cookie_params/tutorial001.py!}
+ ```
+
+## Объявление параметров `Cookie`
+
+Затем объявляйте параметры cookie, используя ту же структуру, что и с `Path` и `Query`.
+
+Первое значение - это значение по умолчанию, вы можете передать все дополнительные параметры проверки или аннотации:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/cookie_params/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/cookie_params/tutorial001.py!}
+ ```
+
+!!! note "Технические детали"
+ `Cookie` - это класс, родственный `Path` и `Query`. Он также наследуется от общего класса `Param`.
+
+ Но помните, что когда вы импортируете `Query`, `Path`, `Cookie` и другое из `fastapi`, это фактически функции, которые возвращают специальные классы.
+
+!!! info "Дополнительная информация"
+ Для объявления cookies, вам нужно использовать `Cookie`, иначе параметры будут интерпретированы как параметры запроса.
+
+## Резюме
+
+Объявляйте cookies с помощью `Cookie`, используя тот же общий шаблон, что и `Query`, и `Path`.
diff --git a/docs/ru/docs/tutorial/extra-data-types.md b/docs/ru/docs/tutorial/extra-data-types.md
new file mode 100644
index 000000000..efcbcb38a
--- /dev/null
+++ b/docs/ru/docs/tutorial/extra-data-types.md
@@ -0,0 +1,82 @@
+# Дополнительные типы данных
+
+До сих пор вы использовали простые типы данных, такие как:
+
+* `int`
+* `float`
+* `str`
+* `bool`
+
+Но вы также можете использовать и более сложные типы.
+
+При этом у вас останутся те же возможности , что и до сих пор:
+
+* Отличная поддержка редактора.
+* Преобразование данных из входящих запросов.
+* Преобразование данных для ответа.
+* Валидация данных.
+* Автоматическая аннотация и документация.
+
+## Другие типы данных
+
+Ниже перечислены некоторые из дополнительных типов данных, которые вы можете использовать:
+
+* `UUID`:
+ * Стандартный "Универсальный уникальный идентификатор", используемый в качестве идентификатора во многих базах данных и системах.
+ * В запросах и ответах будет представлен как `str`.
+* `datetime.datetime`:
+ * Встроенный в Python `datetime.datetime`.
+ * В запросах и ответах будет представлен как `str` в формате ISO 8601, например: `2008-09-15T15:53:00+05:00`.
+* `datetime.date`:
+ * Встроенный в Python `datetime.date`.
+ * В запросах и ответах будет представлен как `str` в формате ISO 8601, например: `2008-09-15`.
+* `datetime.time`:
+ * Встроенный в Python `datetime.time`.
+ * В запросах и ответах будет представлен как `str` в формате ISO 8601, например: `14:23:55.003`.
+* `datetime.timedelta`:
+ * Встроенный в Python `datetime.timedelta`.
+ * В запросах и ответах будет представлен в виде общего количества секунд типа `float`.
+ * Pydantic также позволяет представить его как "Кодировку разницы во времени ISO 8601", см. документацию для получения дополнительной информации.
+* `frozenset`:
+ * В запросах и ответах обрабатывается так же, как и `set`:
+ * В запросах будет прочитан список, исключены дубликаты и преобразован в `set`.
+ * В ответах `set` будет преобразован в `list`.
+ * В сгенерированной схеме будет указано, что значения `set` уникальны (с помощью JSON-схемы `uniqueItems`).
+* `bytes`:
+ * Встроенный в Python `bytes`.
+ * В запросах и ответах будет рассматриваться как `str`.
+ * В сгенерированной схеме будет указано, что это `str` в формате `binary`.
+* `Decimal`:
+ * Встроенный в Python `Decimal`.
+ * В запросах и ответах обрабатывается так же, как и `float`.
+* Вы можете проверить все допустимые типы данных pydantic здесь: Типы данных Pydantic.
+
+## Пример
+
+Вот пример *операции пути* с параметрами, который демонстрирует некоторые из вышеперечисленных типов.
+
+=== "Python 3.6 и выше"
+
+ ```Python hl_lines="1 3 12-16"
+ {!> ../../../docs_src/extra_data_types/tutorial001.py!}
+ ```
+
+=== "Python 3.10 и выше"
+
+ ```Python hl_lines="1 2 11-15"
+ {!> ../../../docs_src/extra_data_types/tutorial001_py310.py!}
+ ```
+
+Обратите внимание, что параметры внутри функции имеют свой естественный тип данных, и вы, например, можете выполнять обычные манипуляции с датами, такие как:
+
+=== "Python 3.6 и выше"
+
+ ```Python hl_lines="18-19"
+ {!> ../../../docs_src/extra_data_types/tutorial001.py!}
+ ```
+
+=== "Python 3.10 и выше"
+
+ ```Python hl_lines="17-18"
+ {!> ../../../docs_src/extra_data_types/tutorial001_py310.py!}
+ ```
diff --git a/docs/ru/docs/tutorial/query-params-str-validations.md b/docs/ru/docs/tutorial/query-params-str-validations.md
new file mode 100644
index 000000000..68042db63
--- /dev/null
+++ b/docs/ru/docs/tutorial/query-params-str-validations.md
@@ -0,0 +1,919 @@
+# Query-параметры и валидация строк
+
+**FastAPI** позволяет определять дополнительную информацию и валидацию для ваших параметров.
+
+Давайте рассмотрим следующий пример:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial001.py!}
+ ```
+
+Query-параметр `q` имеет тип `Union[str, None]` (или `str | None` в Python 3.10). Это означает, что входной параметр будет типа `str`, но может быть и `None`. Ещё параметр имеет значение по умолчанию `None`, из-за чего FastAPI определит параметр как необязательный.
+
+!!! note "Технические детали"
+ FastAPI определит параметр `q` как необязательный, потому что его значение по умолчанию `= None`.
+
+ `Union` в `Union[str, None]` позволит редактору кода оказать вам лучшую поддержку и найти ошибки.
+
+## Расширенная валидация
+
+Добавим дополнительное условие валидации параметра `q` - **длина строки не более 50 символов** (условие проверяется всякий раз, когда параметр `q` не является `None`).
+
+### Импорт `Query` и `Annotated`
+
+Чтобы достичь этого, первым делом нам нужно импортировать:
+
+* `Query` из пакета `fastapi`:
+* `Annotated` из пакета `typing` (или из `typing_extensions` для Python ниже 3.9)
+
+=== "Python 3.10+"
+
+ В Python 3.9 или выше, `Annotated` является частью стандартной библиотеки, таким образом вы можете импортировать его из `typing`.
+
+ ```Python hl_lines="1 3"
+ {!> ../../../docs_src/query_params_str_validations/tutorial002_an_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ В версиях Python ниже Python 3.9 `Annotation` импортируется из `typing_extensions`.
+
+ Эта библиотека будет установлена вместе с FastAPI.
+
+ ```Python hl_lines="3-4"
+ {!> ../../../docs_src/query_params_str_validations/tutorial002_an.py!}
+ ```
+
+## `Annotated` как тип для query-параметра `q`
+
+Помните, как ранее я говорил об Annotated? Он может быть использован для добавления метаданных для ваших параметров в разделе [Введение в аннотации типов Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}?
+
+Пришло время использовать их в FastAPI. 🚀
+
+У нас была аннотация следующего типа:
+
+=== "Python 3.10+"
+
+ ```Python
+ q: str | None = None
+ ```
+
+=== "Python 3.6+"
+
+ ```Python
+ q: Union[str, None] = None
+ ```
+
+Вот что мы получим, если обернём это в `Annotated`:
+
+=== "Python 3.10+"
+
+ ```Python
+ q: Annotated[str | None] = None
+ ```
+
+=== "Python 3.6+"
+
+ ```Python
+ q: Annotated[Union[str, None]] = None
+ ```
+
+Обе эти версии означают одно и тоже. `q` - это параметр, который может быть `str` или `None`, и по умолчанию он будет принимать `None`.
+
+Давайте повеселимся. 🎉
+
+## Добавим `Query` в `Annotated` для query-параметра `q`
+
+Теперь, когда у нас есть `Annotated`, где мы можем добавить больше метаданных, добавим `Query` со значением параметра `max_length` равным 50:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial002_an_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial002_an.py!}
+ ```
+
+Обратите внимание, что значение по умолчанию всё ещё `None`, так что параметр остаётся необязательным.
+
+Однако теперь, имея `Query(max_length=50)` внутри `Annotated`, мы говорим FastAPI, что мы хотим извлечь это значение из параметров query-запроса (что произойдёт в любом случае 🤷), и что мы хотим иметь **дополнительные условия валидации** для этого значения (для чего мы и делаем это - чтобы получить дополнительную валидацию). 😎
+
+Теперь FastAPI:
+
+* **Валидирует** (проверяет), что полученные данные состоят максимум из 50 символов
+* Показывает **исчерпывающую ошибку** (будет описание местонахождения ошибки и её причины) для клиента в случаях, когда данные не валидны
+* **Задокументирует** параметр в схему OpenAPI *операции пути* (что будет отображено в **UI автоматической документации**)
+
+## Альтернативный (устаревший) способ задать `Query` как значение по умолчанию
+
+В предыдущих версиях FastAPI (ниже 0.95.0) необходимо было использовать `Query` как значение по умолчанию для query-параметра. Так было вместо размещения его в `Annotated`, так что велика вероятность, что вам встретится такой код. Сейчас объясню.
+
+!!! tip "Подсказка"
+ При написании нового кода и везде где это возможно, используйте `Annotated`, как было описано ранее. У этого способа есть несколько преимуществ (о них дальше) и никаких недостатков. 🍰
+
+Вот как вы могли бы использовать `Query()` в качестве значения по умолчанию параметра вашей функции, установив для параметра `max_length` значение 50:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial002.py!}
+ ```
+
+В таком случае (без использования `Annotated`), мы заменили значение по умолчанию с `None` на `Query()` в функции. Теперь нам нужно установить значение по умолчанию для query-параметра `Query(default=None)`, что необходимо для тех же целей, как когда ранее просто указывалось значение по умолчанию (по крайней мере, для FastAPI).
+
+Таким образом:
+
+```Python
+q: Union[str, None] = Query(default=None)
+```
+
+...делает параметр необязательным со значением по умолчанию `None`, также как это делает:
+
+```Python
+q: Union[str, None] = None
+```
+
+И для Python 3.10 и выше:
+
+```Python
+q: str | None = Query(default=None)
+```
+
+...делает параметр необязательным со значением по умолчанию `None`, также как это делает:
+
+```Python
+q: str | None = None
+```
+
+Но он явно объявляет его как query-параметр.
+
+!!! info "Дополнительная информация"
+ Запомните, важной частью объявления параметра как необязательного является:
+
+ ```Python
+ = None
+ ```
+
+ или:
+
+ ```Python
+ = Query(default=None)
+ ```
+
+ так как `None` указан в качестве значения по умолчанию, параметр будет **необязательным**.
+
+ `Union[str, None]` позволит редактору кода оказать вам лучшую поддержку. Но это не то, на что обращает внимание FastAPI для определения необязательности параметра.
+
+Теперь, мы можем указать больше параметров для `Query`. В данном случае, параметр `max_length` применяется к строкам:
+
+```Python
+q: Union[str, None] = Query(default=None, max_length=50)
+```
+
+Входные данные будут проверены. Если данные недействительны, тогда будет указано на ошибку в запросе (будет описание местонахождения ошибки и её причины). Кроме того, параметр задокументируется в схеме OpenAPI данной *операции пути*.
+
+### Использовать `Query` как значение по умолчанию или добавить в `Annotated`
+
+Когда `Query` используется внутри `Annotated`, вы не можете использовать параметр `default` у `Query`.
+
+Вместо этого, используйте обычное указание значения по умолчанию для параметра функции. Иначе, это будет несовместимо.
+
+Следующий пример не рабочий:
+
+```Python
+q: Annotated[str, Query(default="rick")] = "morty"
+```
+
+...потому что нельзя однозначно определить, что именно должно быть значением по умолчанию: `"rick"` или `"morty"`.
+
+Вам следует использовать (предпочтительно):
+
+```Python
+q: Annotated[str, Query()] = "rick"
+```
+
+...или как в старом коде, который вам может попасться:
+
+```Python
+q: str = Query(default="rick")
+```
+
+### Преимущества `Annotated`
+
+**Рекомендуется использовать `Annotated`** вместо значения по умолчанию в параметрах функции, потому что так **лучше** по нескольким причинам. 🤓
+
+Значение **по умолчанию** у **параметров функции** - это **действительно значение по умолчанию**, что более интуитивно понятно для пользователей Python. 😌
+
+Вы можете **вызвать** ту же функцию в **иных местах** без FastAPI, и она **сработает как ожидается**. Если это **обязательный** параметр (без значения по умолчанию), ваш **редактор кода** сообщит об ошибке. **Python** также укажет на ошибку, если вы вызовете функцию без передачи ей обязательного параметра.
+
+Если вы вместо `Annotated` используете **(устаревший) стиль значений по умолчанию**, тогда при вызове этой функции без FastAPI в **другом месте** вам необходимо **помнить** о передаче аргументов функции, чтобы она работала корректно. В противном случае, значения будут отличаться от тех, что вы ожидаете (например, `QueryInfo` или что-то подобное вместо `str`). И ни ваш редактор кода, ни Python не будут жаловаться на работу этой функции, только когда вычисления внутри дадут сбой.
+
+Так как `Annotated` может принимать более одной аннотации метаданных, то теперь вы можете использовать ту же функцию с другими инструментами, например Typer. 🚀
+
+## Больше валидации
+
+Вы также можете добавить параметр `min_length`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/query_params_str_validations/tutorial003_an.py!}
+ ```
+
+=== "Python 3.10+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial003.py!}
+ ```
+
+## Регулярные выражения
+
+Вы можете определить регулярное выражение, которому должен соответствовать параметр:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/query_params_str_validations/tutorial004_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/query_params_str_validations/tutorial004_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/query_params_str_validations/tutorial004_an.py!}
+ ```
+
+=== "Python 3.10+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial004_py310.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/query_params_str_validations/tutorial004.py!}
+ ```
+
+Данное регулярное выражение проверяет, что полученное значение параметра:
+
+* `^`: начало строки.
+* `fixedquery`: в точности содержит строку `fixedquery`.
+* `$`: конец строки, не имеет символов после `fixedquery`.
+
+Не переживайте, если **"регулярное выражение"** вызывает у вас трудности. Это достаточно сложная тема для многих людей. Вы можете сделать множество вещей без использования регулярных выражений.
+
+Но когда они вам понадобятся, и вы закончите их освоение, то не будет проблемой использовать их в **FastAPI**.
+
+## Значения по умолчанию
+
+Вы точно также можете указать любое значение `по умолчанию`, как ранее указывали `None`.
+
+Например, вы хотите для параметра запроса `q` указать, что он должен состоять минимум из 3 символов (`min_length=3`) и иметь значение по умолчанию `"fixedquery"`:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial005_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial005_an.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial005.py!}
+ ```
+
+!!! note "Технические детали"
+ Наличие значения по умолчанию делает параметр необязательным.
+
+## Обязательный параметр
+
+Когда вам не требуется дополнительная валидация или дополнительные метаданные для параметра запроса, вы можете сделать параметр `q` обязательным просто не указывая значения по умолчанию. Например:
+
+```Python
+q: str
+```
+
+вместо:
+
+```Python
+q: Union[str, None] = None
+```
+
+Но у нас query-параметр определён как `Query`. Например:
+
+=== "Annotated"
+
+ ```Python
+ q: Annotated[Union[str, None], Query(min_length=3)] = None
+ ```
+
+=== "без Annotated"
+
+ ```Python
+ q: Union[str, None] = Query(default=None, min_length=3)
+ ```
+
+В таком случае, чтобы сделать query-параметр `Query` обязательным, вы можете просто не указывать значение по умолчанию:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006_an.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006.py!}
+ ```
+
+ !!! tip "Подсказка"
+ Обратите внимание, что даже когда `Query()` используется как значение по умолчанию для параметра функции, мы не передаём `default=None` в `Query()`.
+
+ Лучше будет использовать версию с `Annotated`. 😉
+
+### Обязательный параметр с Ellipsis (`...`)
+
+Альтернативный способ указать обязательность параметра запроса - это указать параметр `default` через многоточие `...`:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006b_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006b_an.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006b.py!}
+ ```
+
+!!! info "Дополнительная информация"
+ Если вы ранее не сталкивались с `...`: это специальное значение, часть языка Python и называется "Ellipsis".
+
+ Используется в Pydantic и FastAPI для определения, что значение требуется обязательно.
+
+Таким образом, **FastAPI** определяет, что параметр является обязательным.
+
+### Обязательный параметр с `None`
+
+Вы можете определить, что параметр может принимать `None`, но всё ещё является обязательным. Это может потребоваться для того, чтобы пользователи явно указали параметр, даже если его значение будет `None`.
+
+Чтобы этого добиться, вам нужно определить `None` как валидный тип для параметра запроса, но также указать `default=...`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006c_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006c_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006c_an.py!}
+ ```
+
+=== "Python 3.10+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006c_py310.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006c.py!}
+ ```
+
+!!! tip "Подсказка"
+ Pydantic, мощь которого используется в FastAPI для валидации и сериализации, имеет специальное поведение для `Optional` или `Union[Something, None]` без значения по умолчанию. Вы можете узнать об этом больше в документации Pydantic, раздел Обязательные Опциональные поля.
+
+### Использование Pydantic's `Required` вместо Ellipsis (`...`)
+
+Если вас смущает `...`, вы можете использовать `Required` из Pydantic:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="4 10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006d_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="2 9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006d_an.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="2 8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial006d.py!}
+ ```
+
+!!! tip "Подсказка"
+ Запомните, когда вам необходимо объявить query-параметр обязательным, вы можете просто не указывать параметр `default`. Таким образом, вам редко придётся использовать `...` или `Required`.
+
+## Множество значений для query-параметра
+
+Для query-параметра `Query` можно указать, что он принимает список значений (множество значений).
+
+Например, query-параметр `q` может быть указан в URL несколько раз. И если вы ожидаете такой формат запроса, то можете указать это следующим образом:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial011_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial011_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial011_an.py!}
+ ```
+
+=== "Python 3.10+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial011_py310.py!}
+ ```
+
+=== "Python 3.9+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial011_py39.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial011.py!}
+ ```
+
+Затем, получив такой URL:
+
+```
+http://localhost:8000/items/?q=foo&q=bar
+```
+
+вы бы получили несколько значений (`foo` и `bar`), которые относятся к параметру `q`, в виде Python `list` внутри вашей *функции обработки пути*, в *параметре функции* `q`.
+
+Таким образом, ответ на этот URL будет:
+
+```JSON
+{
+ "q": [
+ "foo",
+ "bar"
+ ]
+}
+```
+
+!!! tip "Подсказка"
+ Чтобы объявить query-параметр типом `list`, как в примере выше, вам нужно явно использовать `Query`, иначе он будет интерпретирован как тело запроса.
+
+Интерактивная документация API будет обновлена соответствующим образом, где будет разрешено множество значений:
+
+
+
+### Query-параметр со множеством значений по умолчанию
+
+Вы также можете указать тип `list` со списком значений по умолчанию на случай, если вам их не предоставят:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial012_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial012_an.py!}
+ ```
+
+=== "Python 3.9+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial012_py39.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial012.py!}
+ ```
+
+Если вы перейдёте по ссылке:
+
+```
+http://localhost:8000/items/
+```
+
+значение по умолчанию для `q` будет: `["foo", "bar"]` и ответом для вас будет:
+
+```JSON
+{
+ "q": [
+ "foo",
+ "bar"
+ ]
+}
+```
+
+#### Использование `list`
+
+Вы также можете использовать `list` напрямую вместо `List[str]` (или `list[str]` в Python 3.9+):
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial013_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial013_an.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial013.py!}
+ ```
+
+!!! note "Технические детали"
+ Запомните, что в таком случае, FastAPI не будет проверять содержимое списка.
+
+ Например, для List[int] список будет провалидирован (и задокументирован) на содержание только целочисленных элементов. Но для простого `list` такой проверки не будет.
+
+## Больше метаданных
+
+Вы можете добавить больше информации об query-параметре.
+
+Указанная информация будет включена в генерируемую OpenAPI документацию и использована в пользовательском интерфейсе и внешних инструментах.
+
+!!! note "Технические детали"
+ Имейте в виду, что разные инструменты могут иметь разные уровни поддержки OpenAPI.
+
+ Некоторые из них могут не отображать (на данный момент) всю заявленную дополнительную информацию, хотя в большинстве случаев отсутствующая функция уже запланирована к разработке.
+
+Вы можете указать название query-параметра, используя параметр `title`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial007_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial007_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/query_params_str_validations/tutorial007_an.py!}
+ ```
+
+=== "Python 3.10+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial007_py310.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial007.py!}
+ ```
+
+Добавить описание, используя параметр `description`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="14"
+ {!> ../../../docs_src/query_params_str_validations/tutorial008_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="14"
+ {!> ../../../docs_src/query_params_str_validations/tutorial008_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="15"
+ {!> ../../../docs_src/query_params_str_validations/tutorial008_an.py!}
+ ```
+
+=== "Python 3.10+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/query_params_str_validations/tutorial008_py310.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="13"
+ {!> ../../../docs_src/query_params_str_validations/tutorial008.py!}
+ ```
+
+## Псевдонимы параметров
+
+Представьте, что вы хотите использовать query-параметр с названием `item-query`.
+
+Например:
+
+```
+http://127.0.0.1:8000/items/?item-query=foobaritems
+```
+
+Но `item-query` является невалидным именем переменной в Python.
+
+Наиболее похожее валидное имя `item_query`.
+
+Но вам всё равно необходим `item-query`...
+
+Тогда вы можете объявить `псевдоним`, и этот псевдоним будет использоваться для поиска значения параметра запроса:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial009_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial009_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial009_an.py!}
+ ```
+
+=== "Python 3.10+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial009_py310.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial009.py!}
+ ```
+
+## Устаревшие параметры
+
+Предположим, вы больше не хотите использовать какой-либо параметр.
+
+Вы решили оставить его, потому что клиенты всё ещё им пользуются. Но вы хотите отобразить это в документации как устаревший функционал.
+
+Тогда для `Query` укажите параметр `deprecated=True`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/query_params_str_validations/tutorial010_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/query_params_str_validations/tutorial010_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/query_params_str_validations/tutorial010_an.py!}
+ ```
+
+=== "Python 3.10+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/query_params_str_validations/tutorial010_py310.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/query_params_str_validations/tutorial010.py!}
+ ```
+
+В документации это будет отображено следующим образом:
+
+
+
+## Исключить из OpenAPI
+
+Чтобы исключить query-параметр из генерируемой OpenAPI схемы (а также из системы автоматической генерации документации), укажите в `Query` параметр `include_in_schema=False`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial014_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial014_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/query_params_str_validations/tutorial014_an.py!}
+ ```
+
+=== "Python 3.10+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params_str_validations/tutorial014_py310.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params_str_validations/tutorial014.py!}
+ ```
+
+## Резюме
+
+Вы можете объявлять дополнительные правила валидации и метаданные для ваших параметров запроса.
+
+Общие метаданные:
+
+* `alias`
+* `title`
+* `description`
+* `deprecated`
+* `include_in_schema`
+
+Специфичные правила валидации для строк:
+
+* `min_length`
+* `max_length`
+* `regex`
+
+В рассмотренных примерах показано объявление правил валидации для строковых значений `str`.
+
+В следующих главах вы увидете, как объявлять правила валидации для других типов (например, чисел).
diff --git a/docs/ru/docs/tutorial/response-status-code.md b/docs/ru/docs/tutorial/response-status-code.md
new file mode 100644
index 000000000..b2f9b7704
--- /dev/null
+++ b/docs/ru/docs/tutorial/response-status-code.md
@@ -0,0 +1,89 @@
+# HTTP коды статуса ответа
+
+Вы можете задать HTTP код статуса ответа с помощью параметра `status_code` подобно тому, как вы определяете схему ответа в любой из *операций пути*:
+
+* `@app.get()`
+* `@app.post()`
+* `@app.put()`
+* `@app.delete()`
+* и других.
+
+```Python hl_lines="6"
+{!../../../docs_src/response_status_code/tutorial001.py!}
+```
+
+!!! note "Примечание"
+ Обратите внимание, что `status_code` является атрибутом метода-декоратора (`get`, `post` и т.д.), а не *функции-обработчика пути* в отличие от всех остальных параметров и тела запроса.
+
+Параметр `status_code` принимает число, обозначающее HTTP код статуса ответа.
+
+!!! info "Информация"
+ В качестве значения параметра `status_code` также может использоваться `IntEnum`, например, из библиотеки `http.HTTPStatus` в Python.
+
+Это позволит:
+
+* Возвращать указанный код статуса в ответе.
+* Документировать его как код статуса ответа в OpenAPI схеме (а значит, и в пользовательском интерфейсе):
+
+
+
+!!! note "Примечание"
+ Некоторые коды статуса ответа (см. следующий раздел) указывают на то, что ответ не имеет тела.
+
+ FastAPI знает об этом и создаст документацию OpenAPI, в которой будет указано, что тело ответа отсутствует.
+
+## Об HTTP кодах статуса ответа
+
+!!! note "Примечание"
+ Если вы уже знаете, что представляют собой HTTP коды статуса ответа, можете перейти к следующему разделу.
+
+В протоколе HTTP числовой код состояния из 3 цифр отправляется как часть ответа.
+
+У кодов статуса есть названия, чтобы упростить их распознавание, но важны именно числовые значения.
+
+Кратко о значениях кодов:
+
+* `1XX` – статус-коды информационного типа. Они редко используются разработчиками напрямую. Ответы с этими кодами не могут иметь тела.
+* **`2XX`** – статус-коды, сообщающие об успешной обработке запроса. Они используются чаще всего.
+ * `200` – это код статуса ответа по умолчанию, который означает, что все прошло "OK".
+ * Другим примером может быть статус `201`, "Created". Он обычно используется после создания новой записи в базе данных.
+ * Особый случай – `204`, "No Content". Этот статус ответа используется, когда нет содержимого для возврата клиенту, и поэтому ответ не должен иметь тела.
+* **`3XX`** – статус-коды, сообщающие о перенаправлениях. Ответы с этими кодами статуса могут иметь или не иметь тело, за исключением ответов со статусом `304`, "Not Modified", у которых не должно быть тела.
+* **`4XX`** – статус-коды, сообщающие о клиентской ошибке. Это ещё одна наиболее часто используемая категория.
+ * Пример – код `404` для статуса "Not Found".
+ * Для общих ошибок со стороны клиента можно просто использовать код `400`.
+* `5XX` – статус-коды, сообщающие о серверной ошибке. Они почти никогда не используются разработчиками напрямую. Когда что-то идет не так в какой-то части кода вашего приложения или на сервере, он автоматически вернёт один из 5XX кодов.
+
+!!! tip "Подсказка"
+ Чтобы узнать больше о HTTP кодах статуса и о том, для чего каждый из них предназначен, ознакомьтесь с документацией MDN об HTTP кодах статуса ответа.
+
+## Краткие обозначения для запоминания названий кодов
+
+Рассмотрим предыдущий пример еще раз:
+
+```Python hl_lines="6"
+{!../../../docs_src/response_status_code/tutorial001.py!}
+```
+
+`201` – это код статуса "Создано".
+
+Но вам не обязательно запоминать, что означает каждый из этих кодов.
+
+Для удобства вы можете использовать переменные из `fastapi.status`.
+
+```Python hl_lines="1 6"
+{!../../../docs_src/response_status_code/tutorial002.py!}
+```
+
+Они содержат те же числовые значения, но позволяют использовать подсказки редактора для выбора кода статуса:
+
+
+
+!!! note "Технические детали"
+ Вы также можете использовать `from starlette import status` вместо `from fastapi import status`.
+
+ **FastAPI** позволяет использовать как `starlette.status`, так и `fastapi.status` исключительно для удобства разработчиков. Но поставляется fastapi.status непосредственно из Starlette.
+
+## Изменение кода статуса по умолчанию
+
+Позже, в [Руководстве для продвинутых пользователей](../advanced/response-change-status-code.md){.internal-link target=_blank}, вы узнаете, как возвращать HTTP коды статуса, отличные от используемого здесь кода статуса по умолчанию.
diff --git a/docs/ru/docs/tutorial/testing.md b/docs/ru/docs/tutorial/testing.md
new file mode 100644
index 000000000..3f9005112
--- /dev/null
+++ b/docs/ru/docs/tutorial/testing.md
@@ -0,0 +1,212 @@
+# Тестирование
+
+Благодаря Starlette, тестировать приложения **FastAPI** легко и приятно.
+
+Тестирование основано на библиотеке HTTPX, которая в свою очередь основана на библиотеке Requests, так что все действия знакомы и интуитивно понятны.
+
+Используя эти инструменты, Вы можете напрямую задействовать pytest с **FastAPI**.
+
+## Использование класса `TestClient`
+
+!!! info "Информация"
+ Для использования класса `TestClient` необходимо установить библиотеку `httpx`.
+
+ Например, так: `pip install httpx`.
+
+Импортируйте `TestClient`.
+
+Создайте объект `TestClient`, передав ему в качестве параметра Ваше приложение **FastAPI**.
+
+Создайте функцию, название которой должно начинаться с `test_` (это стандарт из соглашений `pytest`).
+
+Используйте объект `TestClient` так же, как Вы используете `httpx`.
+
+Напишите простое утверждение с `assert` дабы проверить истинность Python-выражения (это тоже стандарт `pytest`).
+
+```Python hl_lines="2 12 15-18"
+{!../../../docs_src/app_testing/tutorial001.py!}
+```
+
+!!! tip "Подсказка"
+ Обратите внимание, что тестирующая функция является обычной `def`, а не асинхронной `async def`.
+
+ И вызов клиента также осуществляется без `await`.
+
+ Это позволяет вам использовать `pytest` без лишних усложнений.
+
+!!! note "Технические детали"
+ Также можно написать `from starlette.testclient import TestClient`.
+
+ **FastAPI** предоставляет тот же самый `starlette.testclient` как `fastapi.testclient`. Это всего лишь небольшое удобство для Вас, как разработчика.
+
+!!! tip "Подсказка"
+ Если для тестирования Вам, помимо запросов к приложению FastAPI, необходимо вызывать асинхронные функции (например, для подключения к базе данных с помощью асинхронного драйвера), то ознакомьтесь со страницей [Асинхронное тестирование](../advanced/async-tests.md){.internal-link target=_blank} в расширенном руководстве.
+
+## Разделение тестов и приложения
+
+В реальном приложении Вы, вероятно, разместите тесты в отдельном файле.
+
+Кроме того, Ваше приложение **FastAPI** может состоять из нескольких файлов, модулей и т.п.
+
+### Файл приложения **FastAPI**
+
+Допустим, структура файлов Вашего приложения похожа на ту, что описана на странице [Более крупные приложения](./bigger-applications.md){.internal-link target=_blank}:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ └── main.py
+```
+
+Здесь файл `main.py` является "точкой входа" в Ваше приложение и содержит инициализацию Вашего приложения **FastAPI**:
+
+
+```Python
+{!../../../docs_src/app_testing/main.py!}
+```
+
+### Файл тестов
+
+Также у Вас может быть файл `test_main.py` содержащий тесты. Можно разместить тестовый файл и файл приложения в одной директории (в директориях для Python-кода желательно размещать и файл `__init__.py`):
+
+``` hl_lines="5"
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+Так как оба файла находятся в одной директории, для импорта объекта приложения из файла `main` в файл `test_main` Вы можете использовать относительный импорт:
+
+```Python hl_lines="3"
+{!../../../docs_src/app_testing/test_main.py!}
+```
+
+...и писать дальше тесты, как и раньше.
+
+## Тестирование: расширенный пример
+
+Теперь давайте расширим наш пример и добавим деталей, чтоб посмотреть, как тестировать различные части приложения.
+
+### Расширенный файл приложения **FastAPI**
+
+Мы продолжим работу с той же файловой структурой, что и ранее:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+Предположим, что в файле `main.py` с приложением **FastAPI** есть несколько **операций пути**.
+
+В нём описана операция `GET`, которая может вернуть ошибку.
+
+Ещё есть операция `POST` и она тоже может вернуть ошибку.
+
+Обе *операции пути* требуют наличия в запросе заголовка `X-Token`.
+
+=== "Python 3.10+"
+
+ ```Python
+ {!> ../../../docs_src/app_testing/app_b_an_py310/main.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python
+ {!> ../../../docs_src/app_testing/app_b_an_py39/main.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python
+ {!> ../../../docs_src/app_testing/app_b_an/main.py!}
+ ```
+
+=== "Python 3.10+ без Annotated"
+
+ !!! tip "Подсказка"
+ По возможности используйте версию с `Annotated`.
+
+ ```Python
+ {!> ../../../docs_src/app_testing/app_b_py310/main.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ По возможности используйте версию с `Annotated`.
+
+ ```Python
+ {!> ../../../docs_src/app_testing/app_b/main.py!}
+ ```
+
+### Расширенный файл тестов
+
+Теперь обновим файл `test_main.py`, добавив в него тестов:
+
+```Python
+{!> ../../../docs_src/app_testing/app_b/test_main.py!}
+```
+
+Если Вы не знаете, как передать информацию в запросе, можете воспользоваться поисковиком (погуглить) и задать вопрос: "Как передать информацию в запросе с помощью `httpx`", можно даже спросить: "Как передать информацию в запросе с помощью `requests`", поскольку дизайн HTTPX основан на дизайне Requests.
+
+Затем Вы просто применяете найденные ответы в тестах.
+
+Например:
+
+* Передаёте *path*-параметры или *query*-параметры, вписав их непосредственно в строку URL.
+* Передаёте JSON в теле запроса, передав Python-объект (например: `dict`) через именованный параметр `json`.
+* Если же Вам необходимо отправить *форму с данными* вместо JSON, то используйте параметр `data` вместо `json`.
+* Для передачи *заголовков*, передайте объект `dict` через параметр `headers`.
+* Для передачи *cookies* также передайте `dict`, но через параметр `cookies`.
+
+Для получения дополнительной информации о передаче данных на бэкенд с помощью `httpx` или `TestClient` ознакомьтесь с документацией HTTPX.
+
+!!! info "Информация"
+ Обратите внимание, что `TestClient` принимает данные, которые можно конвертировать в JSON, но не модели Pydantic.
+
+ Если в Ваших тестах есть модели Pydantic и Вы хотите отправить их в тестируемое приложение, то можете использовать функцию `jsonable_encoder`, описанную на странице [Кодировщик совместимый с JSON](encoder.md){.internal-link target=_blank}.
+
+## Запуск тестов
+
+Далее Вам нужно установить `pytest`:
+
+
+
+```console
+$ pip install pytest
+
+---> 100%
+```
+
+
+
+Он автоматически найдёт все файлы и тесты, выполнит их и предоставит Вам отчёт о результатах тестирования.
+
+Запустите тесты командой `pytest` и увидите результат:
+
+
+
+```console
+$ pytest
+
+================ test session starts ================
+platform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
+rootdir: /home/user/code/superawesome-cli/app
+plugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1
+collected 6 items
+
+---> 100%
+
+test_main.py ...... [100%]
+
+================= 1 passed in 0.03s =================
+```
+
+
diff --git a/docs/ru/mkdocs.yml b/docs/ru/mkdocs.yml
index f35ee968c..93fae36ce 100644
--- a/docs/ru/mkdocs.yml
+++ b/docs/ru/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -62,12 +67,26 @@ nav:
- fastapi-people.md
- python-types.md
- Учебник - руководство пользователя:
+ - tutorial/query-params-str-validations.md
+ - tutorial/body-fields.md
- tutorial/background-tasks.md
+ - tutorial/extra-data-types.md
+ - tutorial/cookie-params.md
+ - tutorial/testing.md
+ - tutorial/response-status-code.md
- async.md
- Развёртывание:
- deployment/index.md
- deployment/versions.md
+ - deployment/https.md
+ - deployment/manually.md
+- project-generation.md
+- alternatives.md
+- history-design-future.md
- external-links.md
+- benchmarks.md
+- help-fastapi.md
+- contributing.md
markdown_extensions:
- toc:
permalink: true
@@ -90,7 +109,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -111,8 +130,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -121,6 +144,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -129,6 +154,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -141,6 +168,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/sq/mkdocs.yml b/docs/sq/mkdocs.yml
index b07f3bc63..092c50816 100644
--- a/docs/sq/mkdocs.yml
+++ b/docs/sq/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -80,7 +85,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -101,8 +106,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -111,6 +120,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -119,6 +130,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -131,6 +144,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/sv/mkdocs.yml b/docs/sv/mkdocs.yml
index 3332d232d..215b32f18 100644
--- a/docs/sv/mkdocs.yml
+++ b/docs/sv/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -80,7 +85,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -101,8 +106,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -111,6 +120,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -119,6 +130,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -131,6 +144,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/ta/mkdocs.yml b/docs/ta/mkdocs.yml
new file mode 100644
index 000000000..4b96d2cad
--- /dev/null
+++ b/docs/ta/mkdocs.yml
@@ -0,0 +1,160 @@
+site_name: FastAPI
+site_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production
+site_url: https://fastapi.tiangolo.com/ta/
+theme:
+ name: material
+ custom_dir: overrides
+ palette:
+ - media: '(prefers-color-scheme: light)'
+ scheme: default
+ primary: teal
+ accent: amber
+ toggle:
+ icon: material/lightbulb
+ name: Switch to light mode
+ - media: '(prefers-color-scheme: dark)'
+ scheme: slate
+ primary: teal
+ accent: amber
+ toggle:
+ icon: material/lightbulb-outline
+ name: Switch to dark mode
+ features:
+ - search.suggest
+ - search.highlight
+ - content.tabs.link
+ icon:
+ repo: fontawesome/brands/github-alt
+ logo: https://fastapi.tiangolo.com/img/icon-white.svg
+ favicon: https://fastapi.tiangolo.com/img/favicon.png
+ language: en
+repo_name: tiangolo/fastapi
+repo_url: https://github.com/tiangolo/fastapi
+edit_uri: ''
+plugins:
+- search
+- markdownextradata:
+ data: data
+nav:
+- FastAPI: index.md
+- Languages:
+ - en: /
+ - az: /az/
+ - cs: /cs/
+ - de: /de/
+ - em: /em/
+ - es: /es/
+ - fa: /fa/
+ - fr: /fr/
+ - he: /he/
+ - hy: /hy/
+ - id: /id/
+ - it: /it/
+ - ja: /ja/
+ - ko: /ko/
+ - lo: /lo/
+ - nl: /nl/
+ - pl: /pl/
+ - pt: /pt/
+ - ru: /ru/
+ - sq: /sq/
+ - sv: /sv/
+ - ta: /ta/
+ - tr: /tr/
+ - uk: /uk/
+ - zh: /zh/
+markdown_extensions:
+- toc:
+ permalink: true
+- markdown.extensions.codehilite:
+ guess_lang: false
+- mdx_include:
+ base_path: docs
+- admonition
+- codehilite
+- extra
+- pymdownx.superfences:
+ custom_fences:
+ - name: mermaid
+ class: mermaid
+ format: !!python/name:pymdownx.superfences.fence_code_format ''
+- pymdownx.tabbed:
+ alternate_style: true
+- attr_list
+- md_in_html
+extra:
+ analytics:
+ provider: google
+ property: G-YNEVN69SC3
+ social:
+ - icon: fontawesome/brands/github-alt
+ link: https://github.com/tiangolo/fastapi
+ - icon: fontawesome/brands/discord
+ link: https://discord.gg/VQjSZaeJmf
+ - icon: fontawesome/brands/twitter
+ link: https://twitter.com/fastapi
+ - icon: fontawesome/brands/linkedin
+ link: https://www.linkedin.com/in/tiangolo
+ - icon: fontawesome/brands/dev
+ link: https://dev.to/tiangolo
+ - icon: fontawesome/brands/medium
+ link: https://medium.com/@tiangolo
+ - icon: fontawesome/solid/globe
+ link: https://tiangolo.com
+ alternate:
+ - link: /
+ name: en - English
+ - link: /az/
+ name: az
+ - link: /cs/
+ name: cs
+ - link: /de/
+ name: de
+ - link: /em/
+ name: 😉
+ - link: /es/
+ name: es - español
+ - link: /fa/
+ name: fa
+ - link: /fr/
+ name: fr - français
+ - link: /he/
+ name: he
+ - link: /hy/
+ name: hy
+ - link: /id/
+ name: id
+ - link: /it/
+ name: it - italiano
+ - link: /ja/
+ name: ja - 日本語
+ - link: /ko/
+ name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
+ - link: /nl/
+ name: nl
+ - link: /pl/
+ name: pl
+ - link: /pt/
+ name: pt - português
+ - link: /ru/
+ name: ru - русский язык
+ - link: /sq/
+ name: sq - shqip
+ - link: /sv/
+ name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
+ - link: /tr/
+ name: tr - Türkçe
+ - link: /uk/
+ name: uk - українська мова
+ - link: /zh/
+ name: zh - 汉语
+extra_css:
+- https://fastapi.tiangolo.com/css/termynal.css
+- https://fastapi.tiangolo.com/css/custom.css
+extra_javascript:
+- https://fastapi.tiangolo.com/js/termynal.js
+- https://fastapi.tiangolo.com/js/custom.js
diff --git a/docs/ta/overrides/.gitignore b/docs/ta/overrides/.gitignore
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs/tr/docs/tutorial/first_steps.md b/docs/tr/docs/tutorial/first_steps.md
new file mode 100644
index 000000000..b39802f5d
--- /dev/null
+++ b/docs/tr/docs/tutorial/first_steps.md
@@ -0,0 +1,336 @@
+# İlk Adımlar
+
+En basit FastAPI dosyası şu şekildedir:
+
+```Python
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+Bunu bir `main.py` dosyasına kopyalayın.
+
+Projeyi çalıştırın:
+
+
+
+```console
+$ uvicorn main:app --reload
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+INFO: Started reloader process [28720]
+INFO: Started server process [28722]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+```
+
+
+
+!!! note
+ `uvicorn main:app` komutu şunu ifade eder:
+
+ * `main`: `main.py` dosyası (the Python "module").
+ * `app`: `main.py` dosyası içerisinde `app = FastAPI()` satırıyla oluşturulan nesne.
+ * `--reload`: Kod değişikliği sonrasında sunucunun yeniden başlatılmasını sağlar. Yalnızca geliştirme için kullanın.
+
+Çıktıda şu şekilde bir satır vardır:
+
+```hl_lines="4"
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+Bu satır, yerel makinenizde uygulamanızın sunulduğu URL'yi gösterir.
+
+### Kontrol Et
+
+Tarayıcınızda http://127.0.0.1:8000 adresini açın.
+
+Bir JSON yanıtı göreceksiniz:
+
+```JSON
+{"message": "Hello World"}
+```
+
+### İnteraktif API dokümantasyonu
+
+http://127.0.0.1:8000/docs adresine gidin.
+
+Otomatik oluşturulmuş( Swagger UI tarafından sağlanan) interaktif bir API dokümanı göreceksiniz:
+
+
+
+### Alternatif API dokümantasyonu
+
+Şimdi, http://127.0.0.1:8000/redoc adresine gidin.
+
+Otomatik oluşturulmuş(ReDoc tarafından sağlanan) bir API dokümanı göreceksiniz:
+
+
+
+### OpenAPI
+
+**FastAPI**, **OpenAPI** standardını kullanarak tüm API'lerinizi açıklayan bir "şema" oluşturur.
+
+#### "Şema"
+
+Bir "şema", bir şeyin tanımı veya açıklamasıdır. Soyut bir açıklamadır, uygulayan kod değildir.
+
+#### API "şemaları"
+
+Bu durumda, OpenAPI, API şemasını nasıl tanımlayacağınızı belirten şartnamelerdir.
+
+Bu şema tanımı, API yollarınızı, aldıkları olası parametreleri vb. içerir.
+
+#### Data "şema"
+
+"Şema" terimi, JSON içeriği gibi bazı verilerin şeklini de ifade edebilir.
+
+Bu durumda, JSON öznitelikleri ve sahip oldukları veri türleri vb. anlamına gelir.
+
+#### OpenAPI and JSON Şema
+
+OpenAPI, API'niz için bir API şeması tanımlar. Ve bu şema, JSON veri şemaları standardı olan **JSON Şema** kullanılarak API'niz tarafından gönderilen ve alınan verilerin tanımlarını (veya "şemalarını") içerir.
+
+#### `openapi.json` kontrol et
+
+OpenAPI şemasının nasıl göründüğünü merak ediyorsanız, FastAPI otomatik olarak tüm API'nizin açıklamalarını içeren bir JSON (şema) oluşturur.
+
+Doğrudan şu adreste görebilirsiniz: http://127.0.0.1:8000/openapi.json.
+
+Aşağıdaki gibi bir şeyle başlayan bir JSON gösterecektir:
+
+```JSON
+{
+ "openapi": "3.0.2",
+ "info": {
+ "title": "FastAPI",
+ "version": "0.1.0"
+ },
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+
+
+
+...
+```
+
+#### OpenAPI ne içindir?
+
+OpenAPI şeması, dahili olarak bulunan iki etkileşimli dokümantasyon sistemine güç veren şeydir.
+
+Ve tamamen OpenAPI'ye dayalı düzinelerce alternatif vardır. **FastAPI** ile oluşturulmuş uygulamanıza bu alternatiflerden herhangi birini kolayca ekleyebilirsiniz.
+
+API'nizle iletişim kuran istemciler için otomatik olarak kod oluşturmak için de kullanabilirsiniz. Örneğin, frontend, mobil veya IoT uygulamaları.
+
+## Adım adım özet
+
+### Adım 1: `FastAPI`yi içe aktarın
+
+```Python hl_lines="1"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+`FastAPI`, API'niz için tüm fonksiyonları sağlayan bir Python sınıfıdır.
+
+!!! note "Teknik Detaylar"
+ `FastAPI` doğrudan `Starlette` kalıtım alan bir sınıftır.
+
+ Tüm Starlette fonksiyonlarını `FastAPI` ile de kullanabilirsiniz.
+
+### Adım 2: Bir `FastAPI` örneği oluşturun
+
+```Python hl_lines="3"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+Burada `app` değişkeni `FastAPI` sınıfının bir örneği olacaktır.
+
+Bu tüm API'yi oluşturmak için ana etkileşim noktası olacaktır.
+
+`uvicorn` komutunda atıfta bulunulan `app` ile aynıdır.
+
+
+
+```console
+$ uvicorn main:app --reload
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Uygulamanızı aşağıdaki gibi oluşturursanız:
+
+```Python hl_lines="3"
+{!../../../docs_src/first_steps/tutorial002.py!}
+```
+
+Ve bunu `main.py` dosyasına koyduktan sonra `uvicorn` komutunu şu şekilde çağırabilirsiniz:
+
+
+
+```console
+$ uvicorn main:my_awesome_api --reload
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+### Adım 3: *Path işlemleri* oluşturmak
+
+#### Path
+
+Burada "Path" URL'de ilk "\" ile başlayan son bölümü ifade eder.
+
+Yani, şu şekilde bir URL'de:
+
+```
+https://example.com/items/foo
+```
+
+... path şöyle olabilir:
+
+```
+/items/foo
+```
+
+!!! info
+ Genellikle bir "path", "endpoint" veya "route" olarak adlandırılabilir.
+
+Bir API oluştururken, "path", "resource" ile "concern" ayırmanın ana yoludur.
+
+#### İşlemler
+
+Burada "işlem" HTTP methodlarından birini ifade eder.
+
+Onlardan biri:
+
+* `POST`
+* `GET`
+* `PUT`
+* `DELETE`
+
+... ve daha egzotik olanları:
+
+* `OPTIONS`
+* `HEAD`
+* `PATCH`
+* `TRACE`
+
+HTTP protokolünde, bu "methodlardan" birini (veya daha fazlasını) kullanarak her path ile iletişim kurabilirsiniz.
+
+---
+
+API'lerinizi oluştururkan, belirli bir işlemi gerçekleştirirken belirli HTTP methodlarını kullanırsınız.
+
+Normalde kullanılan:
+
+* `POST`: veri oluşturmak.
+* `GET`: veri okumak.
+* `PUT`: veriyi güncellemek.
+* `DELETE`: veriyi silmek.
+
+Bu nedenle, OpenAPI'de HTTP methodlarından her birine "işlem" denir.
+
+Bizde onlara "**işlemler**" diyeceğiz.
+
+#### Bir *Path işlem decoratorleri* tanımlanmak
+
+```Python hl_lines="6"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+`@app.get("/")` **FastAPI'ye** aşağıdaki fonksiyonun adresine giden istekleri işlemekten sorumlu olduğunu söyler:
+
+* path `/`
+* get
işlemi kullanılarak
+
+
+!!! info "`@decorator` Bilgisi"
+ Python `@something` şeklinde ifadeleri "decorator" olarak adlandırır.
+
+ Decoratoru bir fonksiyonun üzerine koyarsınız. Dekoratif bir şapka gibi (Sanırım terim buradan gelmektedir).
+
+ Bir "decorator" fonksiyonu alır ve bazı işlemler gerçekleştir.
+
+ Bizim durumumzda decarator **FastAPI'ye** fonksiyonun bir `get` işlemi ile `/` pathine geldiğini söyler.
+
+ Bu **path işlem decoratordür**
+
+Ayrıca diğer işlemleri de kullanabilirsiniz:
+
+* `@app.post()`
+* `@app.put()`
+* `@app.delete()`
+
+Ve daha egzotik olanları:
+
+* `@app.options()`
+* `@app.head()`
+* `@app.patch()`
+* `@app.trace()`
+
+!!! tip
+ Her işlemi (HTTP method) istediğiniz gibi kullanmakta özgürsünüz.
+
+ **FastAPI** herhangi bir özel anlamı zorlamaz.
+
+ Buradaki bilgiler bir gereklilik değil, bir kılavuz olarak sunulmaktadır.
+
+ Örneğin, GraphQL kullanırkan normalde tüm işlemleri yalnızca `POST` işlemini kullanarak gerçekleştirirsiniz.
+
+### Adım 4: **path işlem fonksiyonunu** tanımlayın
+
+Aşağıdakiler bizim **path işlem fonksiyonlarımızdır**:
+
+* **path**: `/`
+* **işlem**: `get`
+* **function**: "decorator"ün altındaki fonksiyondur (`@app.get("/")` altında).
+
+```Python hl_lines="7"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+Bu bir Python fonksiyonudur.
+
+Bir `GET` işlemi kullanarak "`/`" URL'sine bir istek geldiğinde **FastAPI** tarafından çağrılır.
+
+Bu durumda bir `async` fonksiyonudur.
+
+---
+
+Bunu `async def` yerine normal bir fonksiyon olarakta tanımlayabilirsiniz.
+
+```Python hl_lines="7"
+{!../../../docs_src/first_steps/tutorial003.py!}
+```
+
+!!! note
+
+ Eğer farkı bilmiyorsanız, [Async: *"Acelesi var?"*](../async.md#in-a-hurry){.internal-link target=_blank} kontrol edebilirsiniz.
+
+### Adım 5: İçeriği geri döndürün
+
+
+```Python hl_lines="8"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+Bir `dict`, `list` döndürebilir veya `str`, `int` gibi tekil değerler döndürebilirsiniz.
+
+Ayrıca, Pydantic modellerini de döndürebilirsiniz. (Bununla ilgili daha sonra ayrıntılı bilgi göreceksiniz.)
+
+Otomatik olarak JSON'a dönüştürülecek(ORM'ler vb. dahil) başka birçok nesne ve model vardır. En beğendiklerinizi kullanmayı deneyin, yüksek ihtimalle destekleniyordur.
+
+## Özet
+
+* `FastAPI`'yi içe aktarın.
+* Bir `app` örneği oluşturun.
+* **path işlem decorator** yazın. (`@app.get("/")` gibi)
+* **path işlem fonksiyonu** yazın. (`def root(): ...` gibi)
+* Development sunucunuzu çalıştırın. (`uvicorn main:app --reload` gibi)
diff --git a/docs/tr/mkdocs.yml b/docs/tr/mkdocs.yml
index e29d25936..5811f793e 100644
--- a/docs/tr/mkdocs.yml
+++ b/docs/tr/mkdocs.yml
@@ -40,27 +40,34 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
- features.md
- fastapi-people.md
- python-types.md
+- Tutorial - User Guide:
+ - tutorial/first-steps.md
markdown_extensions:
- toc:
permalink: true
@@ -83,7 +90,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -104,8 +111,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -114,6 +125,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -122,6 +135,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -134,6 +149,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml
index 711328771..5e22570b1 100644
--- a/docs/uk/mkdocs.yml
+++ b/docs/uk/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -80,7 +85,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -101,8 +106,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -111,6 +120,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -119,6 +130,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -131,6 +144,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs/zh/docs/benchmarks.md b/docs/zh/docs/benchmarks.md
index 8991c72cd..71e8d4838 100644
--- a/docs/zh/docs/benchmarks.md
+++ b/docs/zh/docs/benchmarks.md
@@ -1,6 +1,6 @@
# 基准测试
-第三方机构 TechEmpower 的基准测试表明在 Uvicorn 下运行的 **FastAPI** 应用程序是 可用的最快的 Python 框架之一,仅次与 Starlette 和 Uvicorn 本身 (由 FastAPI 内部使用)。(*)
+第三方机构 TechEmpower 的基准测试表明在 Uvicorn 下运行的 **FastAPI** 应用程序是 可用的最快的 Python 框架之一,仅次于 Starlette 和 Uvicorn 本身 (由 FastAPI 内部使用)。(*)
但是在查看基准得分和对比时,请注意以下几点。
diff --git a/docs/zh/docs/index.md b/docs/zh/docs/index.md
index 7901e9c2c..4db3ef10c 100644
--- a/docs/zh/docs/index.md
+++ b/docs/zh/docs/index.md
@@ -28,7 +28,7 @@ FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框
关键特性:
-* **快速**:可与 **NodeJS** 和 **Go** 比肩的极高性能(归功于 Starlette 和 Pydantic)。[最快的 Python web 框架之一](#_11)。
+* **快速**:可与 **NodeJS** 和 **Go** 并肩的极高性能(归功于 Starlette 和 Pydantic)。[最快的 Python web 框架之一](#_11)。
* **高效编码**:提高功能开发速度约 200% 至 300%。*
* **更少 bug**:减少约 40% 的人为(开发者)导致错误。*
diff --git a/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md
index 5813272ee..f404820df 100644
--- a/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md
+++ b/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md
@@ -6,16 +6,16 @@
在前面的例子中, 我们从依赖项 ("可依赖对象") 中返回了一个 `dict`:
-=== "Python 3.6 以及 以上"
+=== "Python 3.10+"
- ```Python hl_lines="9"
- {!> ../../../docs_src/dependencies/tutorial001.py!}
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/dependencies/tutorial001_py310.py!}
```
-=== "Python 3.10 以及以上"
+=== "Python 3.6+"
- ```Python hl_lines="7"
- {!> ../../../docs_src/dependencies/tutorial001_py310.py!}
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/dependencies/tutorial001.py!}
```
但是后面我们在路径操作函数的参数 `commons` 中得到了一个 `dict`。
@@ -79,46 +79,46 @@ fluffy = Cat(name="Mr Fluffy")
所以,我们可以将上面的依赖项 "可依赖对象" `common_parameters` 更改为类 `CommonQueryParams`:
-=== "Python 3.6 以及 以上"
-
- ```Python hl_lines="11-15"
- {!> ../../../docs_src/dependencies/tutorial002.py!}
- ```
-
-=== "Python 3.10 以及 以上"
+=== "Python 3.10+"
```Python hl_lines="9-13"
{!> ../../../docs_src/dependencies/tutorial002_py310.py!}
```
-注意用于创建类实例的 `__init__` 方法:
-
-=== "Python 3.6 以及 以上"
+=== "Python 3.6+"
- ```Python hl_lines="12"
+ ```Python hl_lines="11-15"
{!> ../../../docs_src/dependencies/tutorial002.py!}
```
-=== "Python 3.10 以及 以上"
+注意用于创建类实例的 `__init__` 方法:
+
+=== "Python 3.10+"
```Python hl_lines="10"
{!> ../../../docs_src/dependencies/tutorial002_py310.py!}
```
-...它与我们以前的 `common_parameters` 具有相同的参数:
-
-=== "Python 3.6 以及 以上"
+=== "Python 3.6+"
- ```Python hl_lines="9"
- {!> ../../../docs_src/dependencies/tutorial001.py!}
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/dependencies/tutorial002.py!}
```
-=== "Python 3.10 以及 以上"
+...它与我们以前的 `common_parameters` 具有相同的参数:
+
+=== "Python 3.10+"
```Python hl_lines="6"
{!> ../../../docs_src/dependencies/tutorial001_py310.py!}
```
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/dependencies/tutorial001.py!}
+ ```
+
这些参数就是 **FastAPI** 用来 "处理" 依赖项的。
在两个例子下,都有:
@@ -133,16 +133,16 @@ fluffy = Cat(name="Mr Fluffy")
现在,您可以使用这个类来声明你的依赖项了。
-=== "Python 3.6 以及 以上"
+=== "Python 3.10+"
- ```Python hl_lines="19"
- {!> ../../../docs_src/dependencies/tutorial002.py!}
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/dependencies/tutorial002_py310.py!}
```
-=== "Python 3.10 以及 以上"
+=== "Python 3.6+"
- ```Python hl_lines="17"
- {!> ../../../docs_src/dependencies/tutorial002_py310.py!}
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/dependencies/tutorial002.py!}
```
**FastAPI** 调用 `CommonQueryParams` 类。这将创建该类的一个 "实例",该实例将作为参数 `commons` 被传递给你的函数。
@@ -183,16 +183,16 @@ commons = Depends(CommonQueryParams)
..就像:
-=== "Python 3.6 以及 以上"
+=== "Python 3.10+"
- ```Python hl_lines="19"
- {!> ../../../docs_src/dependencies/tutorial003.py!}
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/dependencies/tutorial003_py310.py!}
```
-=== "Python 3.10 以及 以上"
+=== "Python 3.6+"
- ```Python hl_lines="17"
- {!> ../../../docs_src/dependencies/tutorial003_py310.py!}
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/dependencies/tutorial003.py!}
```
但是声明类型是被鼓励的,因为那样你的编辑器就会知道将传递什么作为参数 `commons` ,然后它可以帮助你完成代码,类型检查,等等:
@@ -227,16 +227,16 @@ commons: CommonQueryParams = Depends()
同样的例子看起来像这样:
-=== "Python 3.6 以及 以上"
+=== "Python 3.10+"
- ```Python hl_lines="19"
- {!> ../../../docs_src/dependencies/tutorial004.py!}
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/dependencies/tutorial004_py310.py!}
```
-=== "Python 3.10 以及 以上"
+=== "Python 3.6+"
- ```Python hl_lines="17"
- {!> ../../../docs_src/dependencies/tutorial004_py310.py!}
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/dependencies/tutorial004.py!}
```
... **FastAPI** 会知道怎么处理。
diff --git a/docs/zh/docs/tutorial/encoder.md b/docs/zh/docs/tutorial/encoder.md
index cb813940c..76ed846ce 100644
--- a/docs/zh/docs/tutorial/encoder.md
+++ b/docs/zh/docs/tutorial/encoder.md
@@ -20,16 +20,16 @@
它接收一个对象,比如Pydantic模型,并会返回一个JSON兼容的版本:
-=== "Python 3.6 and above"
+=== "Python 3.10+"
- ```Python hl_lines="5 22"
- {!> ../../../docs_src/encoder/tutorial001.py!}
+ ```Python hl_lines="4 21"
+ {!> ../../../docs_src/encoder/tutorial001_py310.py!}
```
-=== "Python 3.10 and above"
+=== "Python 3.6+"
- ```Python hl_lines="4 21"
- {!> ../../../docs_src/encoder/tutorial001_py310.py!}
+ ```Python hl_lines="5 22"
+ {!> ../../../docs_src/encoder/tutorial001.py!}
```
在这个例子中,它将Pydantic模型转换为`dict`,并将`datetime`转换为`str`。
diff --git a/docs/zh/docs/tutorial/request-files.md b/docs/zh/docs/tutorial/request-files.md
index e18d6fc9f..03474907e 100644
--- a/docs/zh/docs/tutorial/request-files.md
+++ b/docs/zh/docs/tutorial/request-files.md
@@ -124,16 +124,16 @@ contents = myfile.file.read()
您可以通过使用标准类型注解并将 None 作为默认值的方式将一个文件参数设为可选:
-=== "Python 3.6 及以上版本"
+=== "Python 3.9+"
- ```Python hl_lines="9 17"
- {!> ../../../docs_src/request_files/tutorial001_02.py!}
+ ```Python hl_lines="7 14"
+ {!> ../../../docs_src/request_files/tutorial001_02_py310.py!}
```
-=== "Python 3.9 及以上版本"
+=== "Python 3.6+"
- ```Python hl_lines="7 14"
- {!> ../../../docs_src/request_files/tutorial001_02_py310.py!}
+ ```Python hl_lines="9 17"
+ {!> ../../../docs_src/request_files/tutorial001_02.py!}
```
## 带有额外元数据的 `UploadFile`
@@ -152,16 +152,16 @@ FastAPI 支持同时上传多个文件。
上传多个文件时,要声明含 `bytes` 或 `UploadFile` 的列表(`List`):
-=== "Python 3.6 及以上版本"
+=== "Python 3.9+"
- ```Python hl_lines="10 15"
- {!> ../../../docs_src/request_files/tutorial002.py!}
+ ```Python hl_lines="8 13"
+ {!> ../../../docs_src/request_files/tutorial002_py39.py!}
```
-=== "Python 3.9 及以上版本"
+=== "Python 3.6+"
- ```Python hl_lines="8 13"
- {!> ../../../docs_src/request_files/tutorial002_py39.py!}
+ ```Python hl_lines="10 15"
+ {!> ../../../docs_src/request_files/tutorial002.py!}
```
接收的也是含 `bytes` 或 `UploadFile` 的列表(`list`)。
@@ -177,16 +177,16 @@ FastAPI 支持同时上传多个文件。
和之前的方式一样, 您可以为 `File()` 设置额外参数, 即使是 `UploadFile`:
-=== "Python 3.6 及以上版本"
+=== "Python 3.9+"
- ```Python hl_lines="18"
- {!> ../../../docs_src/request_files/tutorial003.py!}
+ ```Python hl_lines="16"
+ {!> ../../../docs_src/request_files/tutorial003_py39.py!}
```
-=== "Python 3.9 及以上版本"
+=== "Python 3.6+"
- ```Python hl_lines="16"
- {!> ../../../docs_src/request_files/tutorial003_py39.py!}
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/request_files/tutorial003.py!}
```
## 小结
diff --git a/docs/zh/docs/tutorial/sql-databases.md b/docs/zh/docs/tutorial/sql-databases.md
index 6b354c2b6..482588f94 100644
--- a/docs/zh/docs/tutorial/sql-databases.md
+++ b/docs/zh/docs/tutorial/sql-databases.md
@@ -246,22 +246,22 @@ connect_args={"check_same_thread": False}
但是为了安全起见,`password`不会出现在其他同类 Pydantic*模型*中,例如用户请求时不应该从 API 返回响应中包含它。
-=== "Python 3.6 及以上版本"
+=== "Python 3.10+"
- ```Python hl_lines="3 6-8 11-12 23-24 27-28"
- {!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
+ ```Python hl_lines="1 4-6 9-10 21-22 25-26"
+ {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
```
-=== "Python 3.9 及以上版本"
+=== "Python 3.9+"
```Python hl_lines="3 6-8 11-12 23-24 27-28"
{!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!}
```
-=== "Python 3.10 及以上版本"
+=== "Python 3.6+"
- ```Python hl_lines="1 4-6 9-10 21-22 25-26"
- {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
+ ```Python hl_lines="3 6-8 11-12 23-24 27-28"
+ {!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
```
#### SQLAlchemy 风格和 Pydantic 风格
@@ -290,22 +290,22 @@ name: str
不仅是这些项目的 ID,还有我们在 Pydantic*模型*中定义的用于读取项目的所有数据:`Item`.
-=== "Python 3.6 及以上版本"
+=== "Python 3.10+"
- ```Python hl_lines="15-17 31-34"
- {!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
+ ```Python hl_lines="13-15 29-32"
+ {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
```
-=== "Python 3.9 及以上版本"
+=== "Python 3.9+"
```Python hl_lines="15-17 31-34"
{!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!}
```
-=== "Python 3.10 及以上版本"
+=== "Python 3.6+"
- ```Python hl_lines="13-15 29-32"
- {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
+ ```Python hl_lines="15-17 31-34"
+ {!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
```
!!! tip
@@ -319,22 +319,22 @@ name: str
在`Config`类中,设置属性`orm_mode = True`。
-=== "Python 3.6 及以上版本"
+=== "Python 3.10+"
- ```Python hl_lines="15 19-20 31 36-37"
- {!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
+ ```Python hl_lines="13 17-18 29 34-35"
+ {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
```
-=== "Python 3.9 及以上版本"
+=== "Python 3.9+"
```Python hl_lines="15 19-20 31 36-37"
{!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!}
```
-=== "Python 3.10 及以上版本"
+=== "Python 3.6+"
- ```Python hl_lines="13 17-18 29 34-35"
- {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
+ ```Python hl_lines="15 19-20 31 36-37"
+ {!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
```
!!! tip
@@ -465,16 +465,16 @@ current_user.items
以非常简单的方式创建数据库表:
-=== "Python 3.6 及以上版本"
+=== "Python 3.9+"
- ```Python hl_lines="9"
- {!> ../../../docs_src/sql_databases/sql_app/main.py!}
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
-=== "Python 3.9 及以上版本"
+=== "Python 3.6+"
- ```Python hl_lines="7"
- {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
#### Alembic 注意
@@ -499,16 +499,16 @@ current_user.items
我们的依赖项将创建一个新的 SQLAlchemy `SessionLocal`,它将在单个请求中使用,然后在请求完成后关闭它。
-=== "Python 3.6 及以上版本"
+=== "Python 3.9+"
- ```Python hl_lines="15-20"
- {!> ../../../docs_src/sql_databases/sql_app/main.py!}
+ ```Python hl_lines="13-18"
+ {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
-=== "Python 3.9 及以上版本"
+=== "Python 3.6+"
- ```Python hl_lines="13-18"
- {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
+ ```Python hl_lines="15-20"
+ {!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
!!! info
@@ -524,16 +524,16 @@ current_user.items
*这将为我们在路径操作函数*中提供更好的编辑器支持,因为编辑器将知道`db`参数的类型`Session`:
-=== "Python 3.6 及以上版本"
+=== "Python 3.9+"
- ```Python hl_lines="24 32 38 47 53"
- {!> ../../../docs_src/sql_databases/sql_app/main.py!}
+ ```Python hl_lines="22 30 36 45 51"
+ {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
-=== "Python 3.9 及以上版本"
+=== "Python 3.6+"
- ```Python hl_lines="22 30 36 45 51"
- {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
+ ```Python hl_lines="24 32 38 47 53"
+ {!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
!!! info "技术细节"
@@ -545,16 +545,16 @@ current_user.items
现在,到了最后,编写标准的**FastAPI** *路径操作*代码。
-=== "Python 3.6 及以上版本"
+=== "Python 3.9+"
- ```Python hl_lines="23-28 31-34 37-42 45-49 52-55"
- {!> ../../../docs_src/sql_databases/sql_app/main.py!}
+ ```Python hl_lines="21-26 29-32 35-40 43-47 50-53"
+ {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
-=== "Python 3.9 及以上版本"
+=== "Python 3.6+"
- ```Python hl_lines="21-26 29-32 35-40 43-47 50-53"
- {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
+ ```Python hl_lines="23-28 31-34 37-42 45-49 52-55"
+ {!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
我们在依赖项中的每个请求之前利用`yield`创建数据库会话,然后关闭它。
@@ -638,22 +638,22 @@ def read_user(user_id: int, db: Session = Depends(get_db)):
* `sql_app/schemas.py`:
-=== "Python 3.6 及以上版本"
+=== "Python 3.10+"
```Python
- {!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
+ {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
```
-=== "Python 3.9 及以上版本"
+=== "Python 3.9+"
```Python
{!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!}
```
-=== "Python 3.10 及以上版本"
+=== "Python 3.6+"
```Python
- {!> ../../../docs_src/sql_databases/sql_app_py310/schemas.py!}
+ {!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
```
* `sql_app/crud.py`:
@@ -664,16 +664,16 @@ def read_user(user_id: int, db: Session = Depends(get_db)):
* `sql_app/main.py`:
-=== "Python 3.6 及以上版本"
+=== "Python 3.9+"
```Python
- {!> ../../../docs_src/sql_databases/sql_app/main.py!}
+ {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
-=== "Python 3.9 及以上版本"
+=== "Python 3.6+"
```Python
- {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
+ {!> ../../../docs_src/sql_databases/sql_app/main.py!}
```
## 执行项目
@@ -723,16 +723,16 @@ $ uvicorn sql_app.main:app --reload
我们将添加中间件(只是一个函数)将为每个请求创建一个新的 SQLAlchemy`SessionLocal`,将其添加到请求中,然后在请求完成后关闭它。
-=== "Python 3.6 及以上版本"
+=== "Python 3.9+"
- ```Python hl_lines="14-22"
- {!> ../../../docs_src/sql_databases/sql_app/alt_main.py!}
+ ```Python hl_lines="12-20"
+ {!> ../../../docs_src/sql_databases/sql_app_py39/alt_main.py!}
```
-=== "Python 3.9 及以上版本"
+=== "Python 3.6+"
- ```Python hl_lines="12-20"
- {!> ../../../docs_src/sql_databases/sql_app_py39/alt_main.py!}
+ ```Python hl_lines="14-22"
+ {!> ../../../docs_src/sql_databases/sql_app/alt_main.py!}
```
!!! info
diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml
index f4c3c0ec1..ef7ab1fd9 100644
--- a/docs/zh/mkdocs.yml
+++ b/docs/zh/mkdocs.yml
@@ -40,21 +40,26 @@ nav:
- Languages:
- en: /
- az: /az/
+ - cs: /cs/
- de: /de/
+ - em: /em/
- es: /es/
- fa: /fa/
- fr: /fr/
- he: /he/
+ - hy: /hy/
- id: /id/
- it: /it/
- ja: /ja/
- ko: /ko/
+ - lo: /lo/
- nl: /nl/
- pl: /pl/
- pt: /pt/
- ru: /ru/
- sq: /sq/
- sv: /sv/
+ - ta: /ta/
- tr: /tr/
- uk: /uk/
- zh: /zh/
@@ -137,7 +142,7 @@ markdown_extensions:
extra:
analytics:
provider: google
- property: UA-133183413-1
+ property: G-YNEVN69SC3
social:
- icon: fontawesome/brands/github-alt
link: https://github.com/tiangolo/fastapi
@@ -158,8 +163,12 @@ extra:
name: en - English
- link: /az/
name: az
+ - link: /cs/
+ name: cs
- link: /de/
name: de
+ - link: /em/
+ name: 😉
- link: /es/
name: es - español
- link: /fa/
@@ -168,6 +177,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -176,6 +187,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -188,6 +201,8 @@ extra:
name: sq - shqip
- link: /sv/
name: sv - svenska
+ - link: /ta/
+ name: ta - தமிழ்
- link: /tr/
name: tr - Türkçe
- link: /uk/
diff --git a/docs_src/additional_status_codes/tutorial001_an.py b/docs_src/additional_status_codes/tutorial001_an.py
new file mode 100644
index 000000000..b5ad6a16b
--- /dev/null
+++ b/docs_src/additional_status_codes/tutorial001_an.py
@@ -0,0 +1,26 @@
+from typing import Union
+
+from fastapi import Body, FastAPI, status
+from fastapi.responses import JSONResponse
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+items = {"foo": {"name": "Fighters", "size": 6}, "bar": {"name": "Tenders", "size": 3}}
+
+
+@app.put("/items/{item_id}")
+async def upsert_item(
+ item_id: str,
+ name: Annotated[Union[str, None], Body()] = None,
+ size: Annotated[Union[int, None], Body()] = None,
+):
+ if item_id in items:
+ item = items[item_id]
+ item["name"] = name
+ item["size"] = size
+ return item
+ else:
+ item = {"name": name, "size": size}
+ items[item_id] = item
+ return JSONResponse(status_code=status.HTTP_201_CREATED, content=item)
diff --git a/docs_src/additional_status_codes/tutorial001_an_py310.py b/docs_src/additional_status_codes/tutorial001_an_py310.py
new file mode 100644
index 000000000..1865074a1
--- /dev/null
+++ b/docs_src/additional_status_codes/tutorial001_an_py310.py
@@ -0,0 +1,25 @@
+from typing import Annotated
+
+from fastapi import Body, FastAPI, status
+from fastapi.responses import JSONResponse
+
+app = FastAPI()
+
+items = {"foo": {"name": "Fighters", "size": 6}, "bar": {"name": "Tenders", "size": 3}}
+
+
+@app.put("/items/{item_id}")
+async def upsert_item(
+ item_id: str,
+ name: Annotated[str | None, Body()] = None,
+ size: Annotated[int | None, Body()] = None,
+):
+ if item_id in items:
+ item = items[item_id]
+ item["name"] = name
+ item["size"] = size
+ return item
+ else:
+ item = {"name": name, "size": size}
+ items[item_id] = item
+ return JSONResponse(status_code=status.HTTP_201_CREATED, content=item)
diff --git a/docs_src/additional_status_codes/tutorial001_an_py39.py b/docs_src/additional_status_codes/tutorial001_an_py39.py
new file mode 100644
index 000000000..89653dd8a
--- /dev/null
+++ b/docs_src/additional_status_codes/tutorial001_an_py39.py
@@ -0,0 +1,25 @@
+from typing import Annotated, Union
+
+from fastapi import Body, FastAPI, status
+from fastapi.responses import JSONResponse
+
+app = FastAPI()
+
+items = {"foo": {"name": "Fighters", "size": 6}, "bar": {"name": "Tenders", "size": 3}}
+
+
+@app.put("/items/{item_id}")
+async def upsert_item(
+ item_id: str,
+ name: Annotated[Union[str, None], Body()] = None,
+ size: Annotated[Union[int, None], Body()] = None,
+):
+ if item_id in items:
+ item = items[item_id]
+ item["name"] = name
+ item["size"] = size
+ return item
+ else:
+ item = {"name": name, "size": size}
+ items[item_id] = item
+ return JSONResponse(status_code=status.HTTP_201_CREATED, content=item)
diff --git a/docs_src/additional_status_codes/tutorial001_py310.py b/docs_src/additional_status_codes/tutorial001_py310.py
new file mode 100644
index 000000000..38bfa455b
--- /dev/null
+++ b/docs_src/additional_status_codes/tutorial001_py310.py
@@ -0,0 +1,23 @@
+from fastapi import Body, FastAPI, status
+from fastapi.responses import JSONResponse
+
+app = FastAPI()
+
+items = {"foo": {"name": "Fighters", "size": 6}, "bar": {"name": "Tenders", "size": 3}}
+
+
+@app.put("/items/{item_id}")
+async def upsert_item(
+ item_id: str,
+ name: str | None = Body(default=None),
+ size: int | None = Body(default=None),
+):
+ if item_id in items:
+ item = items[item_id]
+ item["name"] = name
+ item["size"] = size
+ return item
+ else:
+ item = {"name": name, "size": size}
+ items[item_id] = item
+ return JSONResponse(status_code=status.HTTP_201_CREATED, content=item)
diff --git a/docs_src/app_testing/app_b_an/__init__.py b/docs_src/app_testing/app_b_an/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs_src/app_testing/app_b_an/main.py b/docs_src/app_testing/app_b_an/main.py
new file mode 100644
index 000000000..c63134fc9
--- /dev/null
+++ b/docs_src/app_testing/app_b_an/main.py
@@ -0,0 +1,39 @@
+from typing import Union
+
+from fastapi import FastAPI, Header, HTTPException
+from pydantic import BaseModel
+from typing_extensions import Annotated
+
+fake_secret_token = "coneofsilence"
+
+fake_db = {
+ "foo": {"id": "foo", "title": "Foo", "description": "There goes my hero"},
+ "bar": {"id": "bar", "title": "Bar", "description": "The bartenders"},
+}
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ id: str
+ title: str
+ description: Union[str, None] = None
+
+
+@app.get("/items/{item_id}", response_model=Item)
+async def read_main(item_id: str, x_token: Annotated[str, Header()]):
+ if x_token != fake_secret_token:
+ raise HTTPException(status_code=400, detail="Invalid X-Token header")
+ if item_id not in fake_db:
+ raise HTTPException(status_code=404, detail="Item not found")
+ return fake_db[item_id]
+
+
+@app.post("/items/", response_model=Item)
+async def create_item(item: Item, x_token: Annotated[str, Header()]):
+ if x_token != fake_secret_token:
+ raise HTTPException(status_code=400, detail="Invalid X-Token header")
+ if item.id in fake_db:
+ raise HTTPException(status_code=400, detail="Item already exists")
+ fake_db[item.id] = item
+ return item
diff --git a/docs_src/app_testing/app_b_an/test_main.py b/docs_src/app_testing/app_b_an/test_main.py
new file mode 100644
index 000000000..d186b8ecb
--- /dev/null
+++ b/docs_src/app_testing/app_b_an/test_main.py
@@ -0,0 +1,65 @@
+from fastapi.testclient import TestClient
+
+from .main import app
+
+client = TestClient(app)
+
+
+def test_read_item():
+ response = client.get("/items/foo", headers={"X-Token": "coneofsilence"})
+ assert response.status_code == 200
+ assert response.json() == {
+ "id": "foo",
+ "title": "Foo",
+ "description": "There goes my hero",
+ }
+
+
+def test_read_item_bad_token():
+ response = client.get("/items/foo", headers={"X-Token": "hailhydra"})
+ assert response.status_code == 400
+ assert response.json() == {"detail": "Invalid X-Token header"}
+
+
+def test_read_inexistent_item():
+ response = client.get("/items/baz", headers={"X-Token": "coneofsilence"})
+ assert response.status_code == 404
+ assert response.json() == {"detail": "Item not found"}
+
+
+def test_create_item():
+ response = client.post(
+ "/items/",
+ headers={"X-Token": "coneofsilence"},
+ json={"id": "foobar", "title": "Foo Bar", "description": "The Foo Barters"},
+ )
+ assert response.status_code == 200
+ assert response.json() == {
+ "id": "foobar",
+ "title": "Foo Bar",
+ "description": "The Foo Barters",
+ }
+
+
+def test_create_item_bad_token():
+ response = client.post(
+ "/items/",
+ headers={"X-Token": "hailhydra"},
+ json={"id": "bazz", "title": "Bazz", "description": "Drop the bazz"},
+ )
+ assert response.status_code == 400
+ assert response.json() == {"detail": "Invalid X-Token header"}
+
+
+def test_create_existing_item():
+ response = client.post(
+ "/items/",
+ headers={"X-Token": "coneofsilence"},
+ json={
+ "id": "foo",
+ "title": "The Foo ID Stealers",
+ "description": "There goes my stealer",
+ },
+ )
+ assert response.status_code == 400
+ assert response.json() == {"detail": "Item already exists"}
diff --git a/docs_src/app_testing/app_b_an_py310/__init__.py b/docs_src/app_testing/app_b_an_py310/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs_src/app_testing/app_b_an_py310/main.py b/docs_src/app_testing/app_b_an_py310/main.py
new file mode 100644
index 000000000..48c27a0b8
--- /dev/null
+++ b/docs_src/app_testing/app_b_an_py310/main.py
@@ -0,0 +1,38 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Header, HTTPException
+from pydantic import BaseModel
+
+fake_secret_token = "coneofsilence"
+
+fake_db = {
+ "foo": {"id": "foo", "title": "Foo", "description": "There goes my hero"},
+ "bar": {"id": "bar", "title": "Bar", "description": "The bartenders"},
+}
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ id: str
+ title: str
+ description: str | None = None
+
+
+@app.get("/items/{item_id}", response_model=Item)
+async def read_main(item_id: str, x_token: Annotated[str, Header()]):
+ if x_token != fake_secret_token:
+ raise HTTPException(status_code=400, detail="Invalid X-Token header")
+ if item_id not in fake_db:
+ raise HTTPException(status_code=404, detail="Item not found")
+ return fake_db[item_id]
+
+
+@app.post("/items/", response_model=Item)
+async def create_item(item: Item, x_token: Annotated[str, Header()]):
+ if x_token != fake_secret_token:
+ raise HTTPException(status_code=400, detail="Invalid X-Token header")
+ if item.id in fake_db:
+ raise HTTPException(status_code=400, detail="Item already exists")
+ fake_db[item.id] = item
+ return item
diff --git a/docs_src/app_testing/app_b_an_py310/test_main.py b/docs_src/app_testing/app_b_an_py310/test_main.py
new file mode 100644
index 000000000..d186b8ecb
--- /dev/null
+++ b/docs_src/app_testing/app_b_an_py310/test_main.py
@@ -0,0 +1,65 @@
+from fastapi.testclient import TestClient
+
+from .main import app
+
+client = TestClient(app)
+
+
+def test_read_item():
+ response = client.get("/items/foo", headers={"X-Token": "coneofsilence"})
+ assert response.status_code == 200
+ assert response.json() == {
+ "id": "foo",
+ "title": "Foo",
+ "description": "There goes my hero",
+ }
+
+
+def test_read_item_bad_token():
+ response = client.get("/items/foo", headers={"X-Token": "hailhydra"})
+ assert response.status_code == 400
+ assert response.json() == {"detail": "Invalid X-Token header"}
+
+
+def test_read_inexistent_item():
+ response = client.get("/items/baz", headers={"X-Token": "coneofsilence"})
+ assert response.status_code == 404
+ assert response.json() == {"detail": "Item not found"}
+
+
+def test_create_item():
+ response = client.post(
+ "/items/",
+ headers={"X-Token": "coneofsilence"},
+ json={"id": "foobar", "title": "Foo Bar", "description": "The Foo Barters"},
+ )
+ assert response.status_code == 200
+ assert response.json() == {
+ "id": "foobar",
+ "title": "Foo Bar",
+ "description": "The Foo Barters",
+ }
+
+
+def test_create_item_bad_token():
+ response = client.post(
+ "/items/",
+ headers={"X-Token": "hailhydra"},
+ json={"id": "bazz", "title": "Bazz", "description": "Drop the bazz"},
+ )
+ assert response.status_code == 400
+ assert response.json() == {"detail": "Invalid X-Token header"}
+
+
+def test_create_existing_item():
+ response = client.post(
+ "/items/",
+ headers={"X-Token": "coneofsilence"},
+ json={
+ "id": "foo",
+ "title": "The Foo ID Stealers",
+ "description": "There goes my stealer",
+ },
+ )
+ assert response.status_code == 400
+ assert response.json() == {"detail": "Item already exists"}
diff --git a/docs_src/app_testing/app_b_an_py39/__init__.py b/docs_src/app_testing/app_b_an_py39/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs_src/app_testing/app_b_an_py39/main.py b/docs_src/app_testing/app_b_an_py39/main.py
new file mode 100644
index 000000000..935a510b7
--- /dev/null
+++ b/docs_src/app_testing/app_b_an_py39/main.py
@@ -0,0 +1,38 @@
+from typing import Annotated, Union
+
+from fastapi import FastAPI, Header, HTTPException
+from pydantic import BaseModel
+
+fake_secret_token = "coneofsilence"
+
+fake_db = {
+ "foo": {"id": "foo", "title": "Foo", "description": "There goes my hero"},
+ "bar": {"id": "bar", "title": "Bar", "description": "The bartenders"},
+}
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ id: str
+ title: str
+ description: Union[str, None] = None
+
+
+@app.get("/items/{item_id}", response_model=Item)
+async def read_main(item_id: str, x_token: Annotated[str, Header()]):
+ if x_token != fake_secret_token:
+ raise HTTPException(status_code=400, detail="Invalid X-Token header")
+ if item_id not in fake_db:
+ raise HTTPException(status_code=404, detail="Item not found")
+ return fake_db[item_id]
+
+
+@app.post("/items/", response_model=Item)
+async def create_item(item: Item, x_token: Annotated[str, Header()]):
+ if x_token != fake_secret_token:
+ raise HTTPException(status_code=400, detail="Invalid X-Token header")
+ if item.id in fake_db:
+ raise HTTPException(status_code=400, detail="Item already exists")
+ fake_db[item.id] = item
+ return item
diff --git a/docs_src/app_testing/app_b_an_py39/test_main.py b/docs_src/app_testing/app_b_an_py39/test_main.py
new file mode 100644
index 000000000..d186b8ecb
--- /dev/null
+++ b/docs_src/app_testing/app_b_an_py39/test_main.py
@@ -0,0 +1,65 @@
+from fastapi.testclient import TestClient
+
+from .main import app
+
+client = TestClient(app)
+
+
+def test_read_item():
+ response = client.get("/items/foo", headers={"X-Token": "coneofsilence"})
+ assert response.status_code == 200
+ assert response.json() == {
+ "id": "foo",
+ "title": "Foo",
+ "description": "There goes my hero",
+ }
+
+
+def test_read_item_bad_token():
+ response = client.get("/items/foo", headers={"X-Token": "hailhydra"})
+ assert response.status_code == 400
+ assert response.json() == {"detail": "Invalid X-Token header"}
+
+
+def test_read_inexistent_item():
+ response = client.get("/items/baz", headers={"X-Token": "coneofsilence"})
+ assert response.status_code == 404
+ assert response.json() == {"detail": "Item not found"}
+
+
+def test_create_item():
+ response = client.post(
+ "/items/",
+ headers={"X-Token": "coneofsilence"},
+ json={"id": "foobar", "title": "Foo Bar", "description": "The Foo Barters"},
+ )
+ assert response.status_code == 200
+ assert response.json() == {
+ "id": "foobar",
+ "title": "Foo Bar",
+ "description": "The Foo Barters",
+ }
+
+
+def test_create_item_bad_token():
+ response = client.post(
+ "/items/",
+ headers={"X-Token": "hailhydra"},
+ json={"id": "bazz", "title": "Bazz", "description": "Drop the bazz"},
+ )
+ assert response.status_code == 400
+ assert response.json() == {"detail": "Invalid X-Token header"}
+
+
+def test_create_existing_item():
+ response = client.post(
+ "/items/",
+ headers={"X-Token": "coneofsilence"},
+ json={
+ "id": "foo",
+ "title": "The Foo ID Stealers",
+ "description": "There goes my stealer",
+ },
+ )
+ assert response.status_code == 400
+ assert response.json() == {"detail": "Item already exists"}
diff --git a/docs_src/app_testing/tutorial002.py b/docs_src/app_testing/tutorial002.py
index b4a9c0586..71c898b3c 100644
--- a/docs_src/app_testing/tutorial002.py
+++ b/docs_src/app_testing/tutorial002.py
@@ -10,7 +10,7 @@ async def read_main():
return {"msg": "Hello World"}
-@app.websocket_route("/ws")
+@app.websocket("/ws")
async def websocket(websocket: WebSocket):
await websocket.accept()
await websocket.send_json({"msg": "Hello WebSocket"})
diff --git a/docs_src/background_tasks/tutorial002_an.py b/docs_src/background_tasks/tutorial002_an.py
new file mode 100644
index 000000000..f63502b09
--- /dev/null
+++ b/docs_src/background_tasks/tutorial002_an.py
@@ -0,0 +1,27 @@
+from typing import Union
+
+from fastapi import BackgroundTasks, Depends, FastAPI
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+def write_log(message: str):
+ with open("log.txt", mode="a") as log:
+ log.write(message)
+
+
+def get_query(background_tasks: BackgroundTasks, q: Union[str, None] = None):
+ if q:
+ message = f"found query: {q}\n"
+ background_tasks.add_task(write_log, message)
+ return q
+
+
+@app.post("/send-notification/{email}")
+async def send_notification(
+ email: str, background_tasks: BackgroundTasks, q: Annotated[str, Depends(get_query)]
+):
+ message = f"message to {email}\n"
+ background_tasks.add_task(write_log, message)
+ return {"message": "Message sent"}
diff --git a/docs_src/background_tasks/tutorial002_an_py310.py b/docs_src/background_tasks/tutorial002_an_py310.py
new file mode 100644
index 000000000..1fc78fbc9
--- /dev/null
+++ b/docs_src/background_tasks/tutorial002_an_py310.py
@@ -0,0 +1,26 @@
+from typing import Annotated
+
+from fastapi import BackgroundTasks, Depends, FastAPI
+
+app = FastAPI()
+
+
+def write_log(message: str):
+ with open("log.txt", mode="a") as log:
+ log.write(message)
+
+
+def get_query(background_tasks: BackgroundTasks, q: str | None = None):
+ if q:
+ message = f"found query: {q}\n"
+ background_tasks.add_task(write_log, message)
+ return q
+
+
+@app.post("/send-notification/{email}")
+async def send_notification(
+ email: str, background_tasks: BackgroundTasks, q: Annotated[str, Depends(get_query)]
+):
+ message = f"message to {email}\n"
+ background_tasks.add_task(write_log, message)
+ return {"message": "Message sent"}
diff --git a/docs_src/background_tasks/tutorial002_an_py39.py b/docs_src/background_tasks/tutorial002_an_py39.py
new file mode 100644
index 000000000..bfdd14875
--- /dev/null
+++ b/docs_src/background_tasks/tutorial002_an_py39.py
@@ -0,0 +1,26 @@
+from typing import Annotated, Union
+
+from fastapi import BackgroundTasks, Depends, FastAPI
+
+app = FastAPI()
+
+
+def write_log(message: str):
+ with open("log.txt", mode="a") as log:
+ log.write(message)
+
+
+def get_query(background_tasks: BackgroundTasks, q: Union[str, None] = None):
+ if q:
+ message = f"found query: {q}\n"
+ background_tasks.add_task(write_log, message)
+ return q
+
+
+@app.post("/send-notification/{email}")
+async def send_notification(
+ email: str, background_tasks: BackgroundTasks, q: Annotated[str, Depends(get_query)]
+):
+ message = f"message to {email}\n"
+ background_tasks.add_task(write_log, message)
+ return {"message": "Message sent"}
diff --git a/docs_src/bigger_applications/app_an/__init__.py b/docs_src/bigger_applications/app_an/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs_src/bigger_applications/app_an/dependencies.py b/docs_src/bigger_applications/app_an/dependencies.py
new file mode 100644
index 000000000..1374c54b3
--- /dev/null
+++ b/docs_src/bigger_applications/app_an/dependencies.py
@@ -0,0 +1,12 @@
+from fastapi import Header, HTTPException
+from typing_extensions import Annotated
+
+
+async def get_token_header(x_token: Annotated[str, Header()]):
+ if x_token != "fake-super-secret-token":
+ raise HTTPException(status_code=400, detail="X-Token header invalid")
+
+
+async def get_query_token(token: str):
+ if token != "jessica":
+ raise HTTPException(status_code=400, detail="No Jessica token provided")
diff --git a/docs_src/bigger_applications/app_an/internal/__init__.py b/docs_src/bigger_applications/app_an/internal/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs_src/bigger_applications/app_an/internal/admin.py b/docs_src/bigger_applications/app_an/internal/admin.py
new file mode 100644
index 000000000..99d3da86b
--- /dev/null
+++ b/docs_src/bigger_applications/app_an/internal/admin.py
@@ -0,0 +1,8 @@
+from fastapi import APIRouter
+
+router = APIRouter()
+
+
+@router.post("/")
+async def update_admin():
+ return {"message": "Admin getting schwifty"}
diff --git a/docs_src/bigger_applications/app_an/main.py b/docs_src/bigger_applications/app_an/main.py
new file mode 100644
index 000000000..ae544a3aa
--- /dev/null
+++ b/docs_src/bigger_applications/app_an/main.py
@@ -0,0 +1,23 @@
+from fastapi import Depends, FastAPI
+
+from .dependencies import get_query_token, get_token_header
+from .internal import admin
+from .routers import items, users
+
+app = FastAPI(dependencies=[Depends(get_query_token)])
+
+
+app.include_router(users.router)
+app.include_router(items.router)
+app.include_router(
+ admin.router,
+ prefix="/admin",
+ tags=["admin"],
+ dependencies=[Depends(get_token_header)],
+ responses={418: {"description": "I'm a teapot"}},
+)
+
+
+@app.get("/")
+async def root():
+ return {"message": "Hello Bigger Applications!"}
diff --git a/docs_src/bigger_applications/app_an/routers/__init__.py b/docs_src/bigger_applications/app_an/routers/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs_src/bigger_applications/app_an/routers/items.py b/docs_src/bigger_applications/app_an/routers/items.py
new file mode 100644
index 000000000..bde9ff4d5
--- /dev/null
+++ b/docs_src/bigger_applications/app_an/routers/items.py
@@ -0,0 +1,38 @@
+from fastapi import APIRouter, Depends, HTTPException
+
+from ..dependencies import get_token_header
+
+router = APIRouter(
+ prefix="/items",
+ tags=["items"],
+ dependencies=[Depends(get_token_header)],
+ responses={404: {"description": "Not found"}},
+)
+
+
+fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}
+
+
+@router.get("/")
+async def read_items():
+ return fake_items_db
+
+
+@router.get("/{item_id}")
+async def read_item(item_id: str):
+ if item_id not in fake_items_db:
+ raise HTTPException(status_code=404, detail="Item not found")
+ return {"name": fake_items_db[item_id]["name"], "item_id": item_id}
+
+
+@router.put(
+ "/{item_id}",
+ tags=["custom"],
+ responses={403: {"description": "Operation forbidden"}},
+)
+async def update_item(item_id: str):
+ if item_id != "plumbus":
+ raise HTTPException(
+ status_code=403, detail="You can only update the item: plumbus"
+ )
+ return {"item_id": item_id, "name": "The great Plumbus"}
diff --git a/docs_src/bigger_applications/app_an/routers/users.py b/docs_src/bigger_applications/app_an/routers/users.py
new file mode 100644
index 000000000..39b3d7e7c
--- /dev/null
+++ b/docs_src/bigger_applications/app_an/routers/users.py
@@ -0,0 +1,18 @@
+from fastapi import APIRouter
+
+router = APIRouter()
+
+
+@router.get("/users/", tags=["users"])
+async def read_users():
+ return [{"username": "Rick"}, {"username": "Morty"}]
+
+
+@router.get("/users/me", tags=["users"])
+async def read_user_me():
+ return {"username": "fakecurrentuser"}
+
+
+@router.get("/users/{username}", tags=["users"])
+async def read_user(username: str):
+ return {"username": username}
diff --git a/docs_src/bigger_applications/app_an_py39/__init__.py b/docs_src/bigger_applications/app_an_py39/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs_src/bigger_applications/app_an_py39/dependencies.py b/docs_src/bigger_applications/app_an_py39/dependencies.py
new file mode 100644
index 000000000..5c7612aa0
--- /dev/null
+++ b/docs_src/bigger_applications/app_an_py39/dependencies.py
@@ -0,0 +1,13 @@
+from typing import Annotated
+
+from fastapi import Header, HTTPException
+
+
+async def get_token_header(x_token: Annotated[str, Header()]):
+ if x_token != "fake-super-secret-token":
+ raise HTTPException(status_code=400, detail="X-Token header invalid")
+
+
+async def get_query_token(token: str):
+ if token != "jessica":
+ raise HTTPException(status_code=400, detail="No Jessica token provided")
diff --git a/docs_src/bigger_applications/app_an_py39/internal/__init__.py b/docs_src/bigger_applications/app_an_py39/internal/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs_src/bigger_applications/app_an_py39/internal/admin.py b/docs_src/bigger_applications/app_an_py39/internal/admin.py
new file mode 100644
index 000000000..99d3da86b
--- /dev/null
+++ b/docs_src/bigger_applications/app_an_py39/internal/admin.py
@@ -0,0 +1,8 @@
+from fastapi import APIRouter
+
+router = APIRouter()
+
+
+@router.post("/")
+async def update_admin():
+ return {"message": "Admin getting schwifty"}
diff --git a/docs_src/bigger_applications/app_an_py39/main.py b/docs_src/bigger_applications/app_an_py39/main.py
new file mode 100644
index 000000000..ae544a3aa
--- /dev/null
+++ b/docs_src/bigger_applications/app_an_py39/main.py
@@ -0,0 +1,23 @@
+from fastapi import Depends, FastAPI
+
+from .dependencies import get_query_token, get_token_header
+from .internal import admin
+from .routers import items, users
+
+app = FastAPI(dependencies=[Depends(get_query_token)])
+
+
+app.include_router(users.router)
+app.include_router(items.router)
+app.include_router(
+ admin.router,
+ prefix="/admin",
+ tags=["admin"],
+ dependencies=[Depends(get_token_header)],
+ responses={418: {"description": "I'm a teapot"}},
+)
+
+
+@app.get("/")
+async def root():
+ return {"message": "Hello Bigger Applications!"}
diff --git a/docs_src/bigger_applications/app_an_py39/routers/__init__.py b/docs_src/bigger_applications/app_an_py39/routers/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs_src/bigger_applications/app_an_py39/routers/items.py b/docs_src/bigger_applications/app_an_py39/routers/items.py
new file mode 100644
index 000000000..bde9ff4d5
--- /dev/null
+++ b/docs_src/bigger_applications/app_an_py39/routers/items.py
@@ -0,0 +1,38 @@
+from fastapi import APIRouter, Depends, HTTPException
+
+from ..dependencies import get_token_header
+
+router = APIRouter(
+ prefix="/items",
+ tags=["items"],
+ dependencies=[Depends(get_token_header)],
+ responses={404: {"description": "Not found"}},
+)
+
+
+fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}
+
+
+@router.get("/")
+async def read_items():
+ return fake_items_db
+
+
+@router.get("/{item_id}")
+async def read_item(item_id: str):
+ if item_id not in fake_items_db:
+ raise HTTPException(status_code=404, detail="Item not found")
+ return {"name": fake_items_db[item_id]["name"], "item_id": item_id}
+
+
+@router.put(
+ "/{item_id}",
+ tags=["custom"],
+ responses={403: {"description": "Operation forbidden"}},
+)
+async def update_item(item_id: str):
+ if item_id != "plumbus":
+ raise HTTPException(
+ status_code=403, detail="You can only update the item: plumbus"
+ )
+ return {"item_id": item_id, "name": "The great Plumbus"}
diff --git a/docs_src/bigger_applications/app_an_py39/routers/users.py b/docs_src/bigger_applications/app_an_py39/routers/users.py
new file mode 100644
index 000000000..39b3d7e7c
--- /dev/null
+++ b/docs_src/bigger_applications/app_an_py39/routers/users.py
@@ -0,0 +1,18 @@
+from fastapi import APIRouter
+
+router = APIRouter()
+
+
+@router.get("/users/", tags=["users"])
+async def read_users():
+ return [{"username": "Rick"}, {"username": "Morty"}]
+
+
+@router.get("/users/me", tags=["users"])
+async def read_user_me():
+ return {"username": "fakecurrentuser"}
+
+
+@router.get("/users/{username}", tags=["users"])
+async def read_user(username: str):
+ return {"username": username}
diff --git a/docs_src/body_fields/tutorial001_an.py b/docs_src/body_fields/tutorial001_an.py
new file mode 100644
index 000000000..15ea1b53d
--- /dev/null
+++ b/docs_src/body_fields/tutorial001_an.py
@@ -0,0 +1,22 @@
+from typing import Union
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel, Field
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = Field(
+ default=None, title="The description of the item", max_length=300
+ )
+ price: float = Field(gt=0, description="The price must be greater than zero")
+ tax: Union[float, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/body_fields/tutorial001_an_py310.py b/docs_src/body_fields/tutorial001_an_py310.py
new file mode 100644
index 000000000..c9d99e1c2
--- /dev/null
+++ b/docs_src/body_fields/tutorial001_an_py310.py
@@ -0,0 +1,21 @@
+from typing import Annotated
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel, Field
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: str | None = Field(
+ default=None, title="The description of the item", max_length=300
+ )
+ price: float = Field(gt=0, description="The price must be greater than zero")
+ tax: float | None = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/body_fields/tutorial001_an_py39.py b/docs_src/body_fields/tutorial001_an_py39.py
new file mode 100644
index 000000000..6ef14470c
--- /dev/null
+++ b/docs_src/body_fields/tutorial001_an_py39.py
@@ -0,0 +1,21 @@
+from typing import Annotated, Union
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel, Field
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = Field(
+ default=None, title="The description of the item", max_length=300
+ )
+ price: float = Field(gt=0, description="The price must be greater than zero")
+ tax: Union[float, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/body_multiple_params/tutorial001_an.py b/docs_src/body_multiple_params/tutorial001_an.py
new file mode 100644
index 000000000..308eee854
--- /dev/null
+++ b/docs_src/body_multiple_params/tutorial001_an.py
@@ -0,0 +1,28 @@
+from typing import Union
+
+from fastapi import FastAPI, Path
+from pydantic import BaseModel
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
+ q: Union[str, None] = None,
+ item: Union[Item, None] = None,
+):
+ results = {"item_id": item_id}
+ if q:
+ results.update({"q": q})
+ if item:
+ results.update({"item": item})
+ return results
diff --git a/docs_src/body_multiple_params/tutorial001_an_py310.py b/docs_src/body_multiple_params/tutorial001_an_py310.py
new file mode 100644
index 000000000..2d79c19c2
--- /dev/null
+++ b/docs_src/body_multiple_params/tutorial001_an_py310.py
@@ -0,0 +1,27 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Path
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: str | None = None
+ price: float
+ tax: float | None = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
+ q: str | None = None,
+ item: Item | None = None,
+):
+ results = {"item_id": item_id}
+ if q:
+ results.update({"q": q})
+ if item:
+ results.update({"item": item})
+ return results
diff --git a/docs_src/body_multiple_params/tutorial001_an_py39.py b/docs_src/body_multiple_params/tutorial001_an_py39.py
new file mode 100644
index 000000000..1c0ac3a7b
--- /dev/null
+++ b/docs_src/body_multiple_params/tutorial001_an_py39.py
@@ -0,0 +1,27 @@
+from typing import Annotated, Union
+
+from fastapi import FastAPI, Path
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
+ q: Union[str, None] = None,
+ item: Union[Item, None] = None,
+):
+ results = {"item_id": item_id}
+ if q:
+ results.update({"q": q})
+ if item:
+ results.update({"item": item})
+ return results
diff --git a/docs_src/body_multiple_params/tutorial003_an.py b/docs_src/body_multiple_params/tutorial003_an.py
new file mode 100644
index 000000000..39ef7340a
--- /dev/null
+++ b/docs_src/body_multiple_params/tutorial003_an.py
@@ -0,0 +1,27 @@
+from typing import Union
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+
+
+class User(BaseModel):
+ username: str
+ full_name: Union[str, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ item_id: int, item: Item, user: User, importance: Annotated[int, Body()]
+):
+ results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
+ return results
diff --git a/docs_src/body_multiple_params/tutorial003_an_py310.py b/docs_src/body_multiple_params/tutorial003_an_py310.py
new file mode 100644
index 000000000..593ff893c
--- /dev/null
+++ b/docs_src/body_multiple_params/tutorial003_an_py310.py
@@ -0,0 +1,26 @@
+from typing import Annotated
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: str | None = None
+ price: float
+ tax: float | None = None
+
+
+class User(BaseModel):
+ username: str
+ full_name: str | None = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ item_id: int, item: Item, user: User, importance: Annotated[int, Body()]
+):
+ results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
+ return results
diff --git a/docs_src/body_multiple_params/tutorial003_an_py39.py b/docs_src/body_multiple_params/tutorial003_an_py39.py
new file mode 100644
index 000000000..042351e0b
--- /dev/null
+++ b/docs_src/body_multiple_params/tutorial003_an_py39.py
@@ -0,0 +1,26 @@
+from typing import Annotated, Union
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+
+
+class User(BaseModel):
+ username: str
+ full_name: Union[str, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ item_id: int, item: Item, user: User, importance: Annotated[int, Body()]
+):
+ results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
+ return results
diff --git a/docs_src/body_multiple_params/tutorial004.py b/docs_src/body_multiple_params/tutorial004.py
index beea7d1e3..8ce4c7a97 100644
--- a/docs_src/body_multiple_params/tutorial004.py
+++ b/docs_src/body_multiple_params/tutorial004.py
@@ -25,7 +25,7 @@ async def update_item(
item: Item,
user: User,
importance: int = Body(gt=0),
- q: Union[str, None] = None
+ q: Union[str, None] = None,
):
results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
if q:
diff --git a/docs_src/body_multiple_params/tutorial004_an.py b/docs_src/body_multiple_params/tutorial004_an.py
new file mode 100644
index 000000000..f6830f392
--- /dev/null
+++ b/docs_src/body_multiple_params/tutorial004_an.py
@@ -0,0 +1,34 @@
+from typing import Union
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+
+
+class User(BaseModel):
+ username: str
+ full_name: Union[str, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ *,
+ item_id: int,
+ item: Item,
+ user: User,
+ importance: Annotated[int, Body(gt=0)],
+ q: Union[str, None] = None,
+):
+ results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/body_multiple_params/tutorial004_an_py310.py b/docs_src/body_multiple_params/tutorial004_an_py310.py
new file mode 100644
index 000000000..cd5c66fef
--- /dev/null
+++ b/docs_src/body_multiple_params/tutorial004_an_py310.py
@@ -0,0 +1,33 @@
+from typing import Annotated
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: str | None = None
+ price: float
+ tax: float | None = None
+
+
+class User(BaseModel):
+ username: str
+ full_name: str | None = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ *,
+ item_id: int,
+ item: Item,
+ user: User,
+ importance: Annotated[int, Body(gt=0)],
+ q: str | None = None,
+):
+ results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/body_multiple_params/tutorial004_an_py39.py b/docs_src/body_multiple_params/tutorial004_an_py39.py
new file mode 100644
index 000000000..567427c03
--- /dev/null
+++ b/docs_src/body_multiple_params/tutorial004_an_py39.py
@@ -0,0 +1,33 @@
+from typing import Annotated, Union
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+
+
+class User(BaseModel):
+ username: str
+ full_name: Union[str, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ *,
+ item_id: int,
+ item: Item,
+ user: User,
+ importance: Annotated[int, Body(gt=0)],
+ q: Union[str, None] = None,
+):
+ results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/body_multiple_params/tutorial004_py310.py b/docs_src/body_multiple_params/tutorial004_py310.py
index 6d495d408..14acbc3b4 100644
--- a/docs_src/body_multiple_params/tutorial004_py310.py
+++ b/docs_src/body_multiple_params/tutorial004_py310.py
@@ -23,7 +23,7 @@ async def update_item(
item: Item,
user: User,
importance: int = Body(gt=0),
- q: str | None = None
+ q: str | None = None,
):
results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
if q:
diff --git a/docs_src/body_multiple_params/tutorial005_an.py b/docs_src/body_multiple_params/tutorial005_an.py
new file mode 100644
index 000000000..dadde80b5
--- /dev/null
+++ b/docs_src/body_multiple_params/tutorial005_an.py
@@ -0,0 +1,20 @@
+from typing import Union
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/body_multiple_params/tutorial005_an_py310.py b/docs_src/body_multiple_params/tutorial005_an_py310.py
new file mode 100644
index 000000000..f97680ba0
--- /dev/null
+++ b/docs_src/body_multiple_params/tutorial005_an_py310.py
@@ -0,0 +1,19 @@
+from typing import Annotated
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: str | None = None
+ price: float
+ tax: float | None = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/body_multiple_params/tutorial005_an_py39.py b/docs_src/body_multiple_params/tutorial005_an_py39.py
new file mode 100644
index 000000000..9a52425c1
--- /dev/null
+++ b/docs_src/body_multiple_params/tutorial005_an_py39.py
@@ -0,0 +1,19 @@
+from typing import Annotated, Union
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/cookie_params/tutorial001_an.py b/docs_src/cookie_params/tutorial001_an.py
new file mode 100644
index 000000000..6d5931229
--- /dev/null
+++ b/docs_src/cookie_params/tutorial001_an.py
@@ -0,0 +1,11 @@
+from typing import Union
+
+from fastapi import Cookie, FastAPI
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(ads_id: Annotated[Union[str, None], Cookie()] = None):
+ return {"ads_id": ads_id}
diff --git a/docs_src/cookie_params/tutorial001_an_py310.py b/docs_src/cookie_params/tutorial001_an_py310.py
new file mode 100644
index 000000000..69ac683fe
--- /dev/null
+++ b/docs_src/cookie_params/tutorial001_an_py310.py
@@ -0,0 +1,10 @@
+from typing import Annotated
+
+from fastapi import Cookie, FastAPI
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(ads_id: Annotated[str | None, Cookie()] = None):
+ return {"ads_id": ads_id}
diff --git a/docs_src/cookie_params/tutorial001_an_py39.py b/docs_src/cookie_params/tutorial001_an_py39.py
new file mode 100644
index 000000000..e18d0a332
--- /dev/null
+++ b/docs_src/cookie_params/tutorial001_an_py39.py
@@ -0,0 +1,10 @@
+from typing import Annotated, Union
+
+from fastapi import Cookie, FastAPI
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(ads_id: Annotated[Union[str, None], Cookie()] = None):
+ return {"ads_id": ads_id}
diff --git a/docs_src/dependencies/tutorial001_02_an.py b/docs_src/dependencies/tutorial001_02_an.py
new file mode 100644
index 000000000..455d60c82
--- /dev/null
+++ b/docs_src/dependencies/tutorial001_02_an.py
@@ -0,0 +1,25 @@
+from typing import Union
+
+from fastapi import Depends, FastAPI
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+async def common_parameters(
+ q: Union[str, None] = None, skip: int = 0, limit: int = 100
+):
+ return {"q": q, "skip": skip, "limit": limit}
+
+
+CommonsDep = Annotated[dict, Depends(common_parameters)]
+
+
+@app.get("/items/")
+async def read_items(commons: CommonsDep):
+ return commons
+
+
+@app.get("/users/")
+async def read_users(commons: CommonsDep):
+ return commons
diff --git a/docs_src/dependencies/tutorial001_02_an_py310.py b/docs_src/dependencies/tutorial001_02_an_py310.py
new file mode 100644
index 000000000..f59637bb2
--- /dev/null
+++ b/docs_src/dependencies/tutorial001_02_an_py310.py
@@ -0,0 +1,22 @@
+from typing import Annotated
+
+from fastapi import Depends, FastAPI
+
+app = FastAPI()
+
+
+async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
+ return {"q": q, "skip": skip, "limit": limit}
+
+
+CommonsDep = Annotated[dict, Depends(common_parameters)]
+
+
+@app.get("/items/")
+async def read_items(commons: CommonsDep):
+ return commons
+
+
+@app.get("/users/")
+async def read_users(commons: CommonsDep):
+ return commons
diff --git a/docs_src/dependencies/tutorial001_02_an_py39.py b/docs_src/dependencies/tutorial001_02_an_py39.py
new file mode 100644
index 000000000..df969ae9c
--- /dev/null
+++ b/docs_src/dependencies/tutorial001_02_an_py39.py
@@ -0,0 +1,24 @@
+from typing import Annotated, Union
+
+from fastapi import Depends, FastAPI
+
+app = FastAPI()
+
+
+async def common_parameters(
+ q: Union[str, None] = None, skip: int = 0, limit: int = 100
+):
+ return {"q": q, "skip": skip, "limit": limit}
+
+
+CommonsDep = Annotated[dict, Depends(common_parameters)]
+
+
+@app.get("/items/")
+async def read_items(commons: CommonsDep):
+ return commons
+
+
+@app.get("/users/")
+async def read_users(commons: CommonsDep):
+ return commons
diff --git a/docs_src/dependencies/tutorial001_an.py b/docs_src/dependencies/tutorial001_an.py
new file mode 100644
index 000000000..81e24fe86
--- /dev/null
+++ b/docs_src/dependencies/tutorial001_an.py
@@ -0,0 +1,22 @@
+from typing import Union
+
+from fastapi import Depends, FastAPI
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+async def common_parameters(
+ q: Union[str, None] = None, skip: int = 0, limit: int = 100
+):
+ return {"q": q, "skip": skip, "limit": limit}
+
+
+@app.get("/items/")
+async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
+ return commons
+
+
+@app.get("/users/")
+async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
+ return commons
diff --git a/docs_src/dependencies/tutorial001_an_py310.py b/docs_src/dependencies/tutorial001_an_py310.py
new file mode 100644
index 000000000..f2e57ae7b
--- /dev/null
+++ b/docs_src/dependencies/tutorial001_an_py310.py
@@ -0,0 +1,19 @@
+from typing import Annotated
+
+from fastapi import Depends, FastAPI
+
+app = FastAPI()
+
+
+async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
+ return {"q": q, "skip": skip, "limit": limit}
+
+
+@app.get("/items/")
+async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
+ return commons
+
+
+@app.get("/users/")
+async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
+ return commons
diff --git a/docs_src/dependencies/tutorial001_an_py39.py b/docs_src/dependencies/tutorial001_an_py39.py
new file mode 100644
index 000000000..5d9fe6ddf
--- /dev/null
+++ b/docs_src/dependencies/tutorial001_an_py39.py
@@ -0,0 +1,21 @@
+from typing import Annotated, Union
+
+from fastapi import Depends, FastAPI
+
+app = FastAPI()
+
+
+async def common_parameters(
+ q: Union[str, None] = None, skip: int = 0, limit: int = 100
+):
+ return {"q": q, "skip": skip, "limit": limit}
+
+
+@app.get("/items/")
+async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
+ return commons
+
+
+@app.get("/users/")
+async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
+ return commons
diff --git a/docs_src/dependencies/tutorial002_an.py b/docs_src/dependencies/tutorial002_an.py
new file mode 100644
index 000000000..964ccf66c
--- /dev/null
+++ b/docs_src/dependencies/tutorial002_an.py
@@ -0,0 +1,26 @@
+from typing import Union
+
+from fastapi import Depends, FastAPI
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
+
+
+class CommonQueryParams:
+ def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
+ self.q = q
+ self.skip = skip
+ self.limit = limit
+
+
+@app.get("/items/")
+async def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]):
+ response = {}
+ if commons.q:
+ response.update({"q": commons.q})
+ items = fake_items_db[commons.skip : commons.skip + commons.limit]
+ response.update({"items": items})
+ return response
diff --git a/docs_src/dependencies/tutorial002_an_py310.py b/docs_src/dependencies/tutorial002_an_py310.py
new file mode 100644
index 000000000..077726312
--- /dev/null
+++ b/docs_src/dependencies/tutorial002_an_py310.py
@@ -0,0 +1,25 @@
+from typing import Annotated
+
+from fastapi import Depends, FastAPI
+
+app = FastAPI()
+
+
+fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
+
+
+class CommonQueryParams:
+ def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
+ self.q = q
+ self.skip = skip
+ self.limit = limit
+
+
+@app.get("/items/")
+async def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]):
+ response = {}
+ if commons.q:
+ response.update({"q": commons.q})
+ items = fake_items_db[commons.skip : commons.skip + commons.limit]
+ response.update({"items": items})
+ return response
diff --git a/docs_src/dependencies/tutorial002_an_py39.py b/docs_src/dependencies/tutorial002_an_py39.py
new file mode 100644
index 000000000..844a23c5a
--- /dev/null
+++ b/docs_src/dependencies/tutorial002_an_py39.py
@@ -0,0 +1,25 @@
+from typing import Annotated, Union
+
+from fastapi import Depends, FastAPI
+
+app = FastAPI()
+
+
+fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
+
+
+class CommonQueryParams:
+ def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
+ self.q = q
+ self.skip = skip
+ self.limit = limit
+
+
+@app.get("/items/")
+async def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]):
+ response = {}
+ if commons.q:
+ response.update({"q": commons.q})
+ items = fake_items_db[commons.skip : commons.skip + commons.limit]
+ response.update({"items": items})
+ return response
diff --git a/docs_src/dependencies/tutorial003_an.py b/docs_src/dependencies/tutorial003_an.py
new file mode 100644
index 000000000..ba8e9f717
--- /dev/null
+++ b/docs_src/dependencies/tutorial003_an.py
@@ -0,0 +1,26 @@
+from typing import Any, Union
+
+from fastapi import Depends, FastAPI
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
+
+
+class CommonQueryParams:
+ def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
+ self.q = q
+ self.skip = skip
+ self.limit = limit
+
+
+@app.get("/items/")
+async def read_items(commons: Annotated[Any, Depends(CommonQueryParams)]):
+ response = {}
+ if commons.q:
+ response.update({"q": commons.q})
+ items = fake_items_db[commons.skip : commons.skip + commons.limit]
+ response.update({"items": items})
+ return response
diff --git a/docs_src/dependencies/tutorial003_an_py310.py b/docs_src/dependencies/tutorial003_an_py310.py
new file mode 100644
index 000000000..44116989b
--- /dev/null
+++ b/docs_src/dependencies/tutorial003_an_py310.py
@@ -0,0 +1,25 @@
+from typing import Annotated, Any
+
+from fastapi import Depends, FastAPI
+
+app = FastAPI()
+
+
+fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
+
+
+class CommonQueryParams:
+ def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
+ self.q = q
+ self.skip = skip
+ self.limit = limit
+
+
+@app.get("/items/")
+async def read_items(commons: Annotated[Any, Depends(CommonQueryParams)]):
+ response = {}
+ if commons.q:
+ response.update({"q": commons.q})
+ items = fake_items_db[commons.skip : commons.skip + commons.limit]
+ response.update({"items": items})
+ return response
diff --git a/docs_src/dependencies/tutorial003_an_py39.py b/docs_src/dependencies/tutorial003_an_py39.py
new file mode 100644
index 000000000..9e9123ad2
--- /dev/null
+++ b/docs_src/dependencies/tutorial003_an_py39.py
@@ -0,0 +1,25 @@
+from typing import Annotated, Any, Union
+
+from fastapi import Depends, FastAPI
+
+app = FastAPI()
+
+
+fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
+
+
+class CommonQueryParams:
+ def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
+ self.q = q
+ self.skip = skip
+ self.limit = limit
+
+
+@app.get("/items/")
+async def read_items(commons: Annotated[Any, Depends(CommonQueryParams)]):
+ response = {}
+ if commons.q:
+ response.update({"q": commons.q})
+ items = fake_items_db[commons.skip : commons.skip + commons.limit]
+ response.update({"items": items})
+ return response
diff --git a/docs_src/dependencies/tutorial004_an.py b/docs_src/dependencies/tutorial004_an.py
new file mode 100644
index 000000000..78881a354
--- /dev/null
+++ b/docs_src/dependencies/tutorial004_an.py
@@ -0,0 +1,26 @@
+from typing import Union
+
+from fastapi import Depends, FastAPI
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
+
+
+class CommonQueryParams:
+ def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
+ self.q = q
+ self.skip = skip
+ self.limit = limit
+
+
+@app.get("/items/")
+async def read_items(commons: Annotated[CommonQueryParams, Depends()]):
+ response = {}
+ if commons.q:
+ response.update({"q": commons.q})
+ items = fake_items_db[commons.skip : commons.skip + commons.limit]
+ response.update({"items": items})
+ return response
diff --git a/docs_src/dependencies/tutorial004_an_py310.py b/docs_src/dependencies/tutorial004_an_py310.py
new file mode 100644
index 000000000..2c009efcc
--- /dev/null
+++ b/docs_src/dependencies/tutorial004_an_py310.py
@@ -0,0 +1,25 @@
+from typing import Annotated
+
+from fastapi import Depends, FastAPI
+
+app = FastAPI()
+
+
+fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
+
+
+class CommonQueryParams:
+ def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
+ self.q = q
+ self.skip = skip
+ self.limit = limit
+
+
+@app.get("/items/")
+async def read_items(commons: Annotated[CommonQueryParams, Depends()]):
+ response = {}
+ if commons.q:
+ response.update({"q": commons.q})
+ items = fake_items_db[commons.skip : commons.skip + commons.limit]
+ response.update({"items": items})
+ return response
diff --git a/docs_src/dependencies/tutorial004_an_py39.py b/docs_src/dependencies/tutorial004_an_py39.py
new file mode 100644
index 000000000..74268626b
--- /dev/null
+++ b/docs_src/dependencies/tutorial004_an_py39.py
@@ -0,0 +1,25 @@
+from typing import Annotated, Union
+
+from fastapi import Depends, FastAPI
+
+app = FastAPI()
+
+
+fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
+
+
+class CommonQueryParams:
+ def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
+ self.q = q
+ self.skip = skip
+ self.limit = limit
+
+
+@app.get("/items/")
+async def read_items(commons: Annotated[CommonQueryParams, Depends()]):
+ response = {}
+ if commons.q:
+ response.update({"q": commons.q})
+ items = fake_items_db[commons.skip : commons.skip + commons.limit]
+ response.update({"items": items})
+ return response
diff --git a/docs_src/dependencies/tutorial005_an.py b/docs_src/dependencies/tutorial005_an.py
new file mode 100644
index 000000000..6785099da
--- /dev/null
+++ b/docs_src/dependencies/tutorial005_an.py
@@ -0,0 +1,26 @@
+from typing import Union
+
+from fastapi import Cookie, Depends, FastAPI
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+def query_extractor(q: Union[str, None] = None):
+ return q
+
+
+def query_or_cookie_extractor(
+ q: Annotated[str, Depends(query_extractor)],
+ last_query: Annotated[Union[str, None], Cookie()] = None,
+):
+ if not q:
+ return last_query
+ return q
+
+
+@app.get("/items/")
+async def read_query(
+ query_or_default: Annotated[str, Depends(query_or_cookie_extractor)]
+):
+ return {"q_or_cookie": query_or_default}
diff --git a/docs_src/dependencies/tutorial005_an_py310.py b/docs_src/dependencies/tutorial005_an_py310.py
new file mode 100644
index 000000000..6c0aa0b36
--- /dev/null
+++ b/docs_src/dependencies/tutorial005_an_py310.py
@@ -0,0 +1,25 @@
+from typing import Annotated
+
+from fastapi import Cookie, Depends, FastAPI
+
+app = FastAPI()
+
+
+def query_extractor(q: str | None = None):
+ return q
+
+
+def query_or_cookie_extractor(
+ q: Annotated[str, Depends(query_extractor)],
+ last_query: Annotated[str | None, Cookie()] = None,
+):
+ if not q:
+ return last_query
+ return q
+
+
+@app.get("/items/")
+async def read_query(
+ query_or_default: Annotated[str, Depends(query_or_cookie_extractor)]
+):
+ return {"q_or_cookie": query_or_default}
diff --git a/docs_src/dependencies/tutorial005_an_py39.py b/docs_src/dependencies/tutorial005_an_py39.py
new file mode 100644
index 000000000..e8887e162
--- /dev/null
+++ b/docs_src/dependencies/tutorial005_an_py39.py
@@ -0,0 +1,25 @@
+from typing import Annotated, Union
+
+from fastapi import Cookie, Depends, FastAPI
+
+app = FastAPI()
+
+
+def query_extractor(q: Union[str, None] = None):
+ return q
+
+
+def query_or_cookie_extractor(
+ q: Annotated[str, Depends(query_extractor)],
+ last_query: Annotated[Union[str, None], Cookie()] = None,
+):
+ if not q:
+ return last_query
+ return q
+
+
+@app.get("/items/")
+async def read_query(
+ query_or_default: Annotated[str, Depends(query_or_cookie_extractor)]
+):
+ return {"q_or_cookie": query_or_default}
diff --git a/docs_src/dependencies/tutorial006_an.py b/docs_src/dependencies/tutorial006_an.py
new file mode 100644
index 000000000..5aaea04d1
--- /dev/null
+++ b/docs_src/dependencies/tutorial006_an.py
@@ -0,0 +1,20 @@
+from fastapi import Depends, FastAPI, Header, HTTPException
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+async def verify_token(x_token: Annotated[str, Header()]):
+ if x_token != "fake-super-secret-token":
+ raise HTTPException(status_code=400, detail="X-Token header invalid")
+
+
+async def verify_key(x_key: Annotated[str, Header()]):
+ if x_key != "fake-super-secret-key":
+ raise HTTPException(status_code=400, detail="X-Key header invalid")
+ return x_key
+
+
+@app.get("/items/", dependencies=[Depends(verify_token), Depends(verify_key)])
+async def read_items():
+ return [{"item": "Foo"}, {"item": "Bar"}]
diff --git a/docs_src/dependencies/tutorial006_an_py39.py b/docs_src/dependencies/tutorial006_an_py39.py
new file mode 100644
index 000000000..11976ed6a
--- /dev/null
+++ b/docs_src/dependencies/tutorial006_an_py39.py
@@ -0,0 +1,21 @@
+from typing import Annotated
+
+from fastapi import Depends, FastAPI, Header, HTTPException
+
+app = FastAPI()
+
+
+async def verify_token(x_token: Annotated[str, Header()]):
+ if x_token != "fake-super-secret-token":
+ raise HTTPException(status_code=400, detail="X-Token header invalid")
+
+
+async def verify_key(x_key: Annotated[str, Header()]):
+ if x_key != "fake-super-secret-key":
+ raise HTTPException(status_code=400, detail="X-Key header invalid")
+ return x_key
+
+
+@app.get("/items/", dependencies=[Depends(verify_token), Depends(verify_key)])
+async def read_items():
+ return [{"item": "Foo"}, {"item": "Bar"}]
diff --git a/docs_src/dependencies/tutorial008_an.py b/docs_src/dependencies/tutorial008_an.py
new file mode 100644
index 000000000..2de86f042
--- /dev/null
+++ b/docs_src/dependencies/tutorial008_an.py
@@ -0,0 +1,26 @@
+from fastapi import Depends
+from typing_extensions import Annotated
+
+
+async def dependency_a():
+ dep_a = generate_dep_a()
+ try:
+ yield dep_a
+ finally:
+ dep_a.close()
+
+
+async def dependency_b(dep_a: Annotated[DepA, Depends(dependency_a)]):
+ dep_b = generate_dep_b()
+ try:
+ yield dep_b
+ finally:
+ dep_b.close(dep_a)
+
+
+async def dependency_c(dep_b: Annotated[DepB, Depends(dependency_b)]):
+ dep_c = generate_dep_c()
+ try:
+ yield dep_c
+ finally:
+ dep_c.close(dep_b)
diff --git a/docs_src/dependencies/tutorial008_an_py39.py b/docs_src/dependencies/tutorial008_an_py39.py
new file mode 100644
index 000000000..acc804c32
--- /dev/null
+++ b/docs_src/dependencies/tutorial008_an_py39.py
@@ -0,0 +1,27 @@
+from typing import Annotated
+
+from fastapi import Depends
+
+
+async def dependency_a():
+ dep_a = generate_dep_a()
+ try:
+ yield dep_a
+ finally:
+ dep_a.close()
+
+
+async def dependency_b(dep_a: Annotated[DepA, Depends(dependency_a)]):
+ dep_b = generate_dep_b()
+ try:
+ yield dep_b
+ finally:
+ dep_b.close(dep_a)
+
+
+async def dependency_c(dep_b: Annotated[DepB, Depends(dependency_b)]):
+ dep_c = generate_dep_c()
+ try:
+ yield dep_c
+ finally:
+ dep_c.close(dep_b)
diff --git a/docs_src/dependencies/tutorial011_an.py b/docs_src/dependencies/tutorial011_an.py
new file mode 100644
index 000000000..6c13d9033
--- /dev/null
+++ b/docs_src/dependencies/tutorial011_an.py
@@ -0,0 +1,22 @@
+from fastapi import Depends, FastAPI
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+class FixedContentQueryChecker:
+ def __init__(self, fixed_content: str):
+ self.fixed_content = fixed_content
+
+ def __call__(self, q: str = ""):
+ if q:
+ return self.fixed_content in q
+ return False
+
+
+checker = FixedContentQueryChecker("bar")
+
+
+@app.get("/query-checker/")
+async def read_query_check(fixed_content_included: Annotated[bool, Depends(checker)]):
+ return {"fixed_content_in_query": fixed_content_included}
diff --git a/docs_src/dependencies/tutorial011_an_py39.py b/docs_src/dependencies/tutorial011_an_py39.py
new file mode 100644
index 000000000..68b7434ec
--- /dev/null
+++ b/docs_src/dependencies/tutorial011_an_py39.py
@@ -0,0 +1,23 @@
+from typing import Annotated
+
+from fastapi import Depends, FastAPI
+
+app = FastAPI()
+
+
+class FixedContentQueryChecker:
+ def __init__(self, fixed_content: str):
+ self.fixed_content = fixed_content
+
+ def __call__(self, q: str = ""):
+ if q:
+ return self.fixed_content in q
+ return False
+
+
+checker = FixedContentQueryChecker("bar")
+
+
+@app.get("/query-checker/")
+async def read_query_check(fixed_content_included: Annotated[bool, Depends(checker)]):
+ return {"fixed_content_in_query": fixed_content_included}
diff --git a/docs_src/dependencies/tutorial012_an.py b/docs_src/dependencies/tutorial012_an.py
new file mode 100644
index 000000000..7541e6bf4
--- /dev/null
+++ b/docs_src/dependencies/tutorial012_an.py
@@ -0,0 +1,26 @@
+from fastapi import Depends, FastAPI, Header, HTTPException
+from typing_extensions import Annotated
+
+
+async def verify_token(x_token: Annotated[str, Header()]):
+ if x_token != "fake-super-secret-token":
+ raise HTTPException(status_code=400, detail="X-Token header invalid")
+
+
+async def verify_key(x_key: Annotated[str, Header()]):
+ if x_key != "fake-super-secret-key":
+ raise HTTPException(status_code=400, detail="X-Key header invalid")
+ return x_key
+
+
+app = FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)])
+
+
+@app.get("/items/")
+async def read_items():
+ return [{"item": "Portal Gun"}, {"item": "Plumbus"}]
+
+
+@app.get("/users/")
+async def read_users():
+ return [{"username": "Rick"}, {"username": "Morty"}]
diff --git a/docs_src/dependencies/tutorial012_an_py39.py b/docs_src/dependencies/tutorial012_an_py39.py
new file mode 100644
index 000000000..7541e6bf4
--- /dev/null
+++ b/docs_src/dependencies/tutorial012_an_py39.py
@@ -0,0 +1,26 @@
+from fastapi import Depends, FastAPI, Header, HTTPException
+from typing_extensions import Annotated
+
+
+async def verify_token(x_token: Annotated[str, Header()]):
+ if x_token != "fake-super-secret-token":
+ raise HTTPException(status_code=400, detail="X-Token header invalid")
+
+
+async def verify_key(x_key: Annotated[str, Header()]):
+ if x_key != "fake-super-secret-key":
+ raise HTTPException(status_code=400, detail="X-Key header invalid")
+ return x_key
+
+
+app = FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)])
+
+
+@app.get("/items/")
+async def read_items():
+ return [{"item": "Portal Gun"}, {"item": "Plumbus"}]
+
+
+@app.get("/users/")
+async def read_users():
+ return [{"username": "Rick"}, {"username": "Morty"}]
diff --git a/docs_src/dependency_testing/tutorial001_an.py b/docs_src/dependency_testing/tutorial001_an.py
new file mode 100644
index 000000000..4c76a87ff
--- /dev/null
+++ b/docs_src/dependency_testing/tutorial001_an.py
@@ -0,0 +1,60 @@
+from typing import Union
+
+from fastapi import Depends, FastAPI
+from fastapi.testclient import TestClient
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+async def common_parameters(
+ q: Union[str, None] = None, skip: int = 0, limit: int = 100
+):
+ return {"q": q, "skip": skip, "limit": limit}
+
+
+@app.get("/items/")
+async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
+ return {"message": "Hello Items!", "params": commons}
+
+
+@app.get("/users/")
+async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
+ return {"message": "Hello Users!", "params": commons}
+
+
+client = TestClient(app)
+
+
+async def override_dependency(q: Union[str, None] = None):
+ return {"q": q, "skip": 5, "limit": 10}
+
+
+app.dependency_overrides[common_parameters] = override_dependency
+
+
+def test_override_in_items():
+ response = client.get("/items/")
+ assert response.status_code == 200
+ assert response.json() == {
+ "message": "Hello Items!",
+ "params": {"q": None, "skip": 5, "limit": 10},
+ }
+
+
+def test_override_in_items_with_q():
+ response = client.get("/items/?q=foo")
+ assert response.status_code == 200
+ assert response.json() == {
+ "message": "Hello Items!",
+ "params": {"q": "foo", "skip": 5, "limit": 10},
+ }
+
+
+def test_override_in_items_with_params():
+ response = client.get("/items/?q=foo&skip=100&limit=200")
+ assert response.status_code == 200
+ assert response.json() == {
+ "message": "Hello Items!",
+ "params": {"q": "foo", "skip": 5, "limit": 10},
+ }
diff --git a/docs_src/dependency_testing/tutorial001_an_py310.py b/docs_src/dependency_testing/tutorial001_an_py310.py
new file mode 100644
index 000000000..f866e7a1b
--- /dev/null
+++ b/docs_src/dependency_testing/tutorial001_an_py310.py
@@ -0,0 +1,57 @@
+from typing import Annotated
+
+from fastapi import Depends, FastAPI
+from fastapi.testclient import TestClient
+
+app = FastAPI()
+
+
+async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
+ return {"q": q, "skip": skip, "limit": limit}
+
+
+@app.get("/items/")
+async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
+ return {"message": "Hello Items!", "params": commons}
+
+
+@app.get("/users/")
+async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
+ return {"message": "Hello Users!", "params": commons}
+
+
+client = TestClient(app)
+
+
+async def override_dependency(q: str | None = None):
+ return {"q": q, "skip": 5, "limit": 10}
+
+
+app.dependency_overrides[common_parameters] = override_dependency
+
+
+def test_override_in_items():
+ response = client.get("/items/")
+ assert response.status_code == 200
+ assert response.json() == {
+ "message": "Hello Items!",
+ "params": {"q": None, "skip": 5, "limit": 10},
+ }
+
+
+def test_override_in_items_with_q():
+ response = client.get("/items/?q=foo")
+ assert response.status_code == 200
+ assert response.json() == {
+ "message": "Hello Items!",
+ "params": {"q": "foo", "skip": 5, "limit": 10},
+ }
+
+
+def test_override_in_items_with_params():
+ response = client.get("/items/?q=foo&skip=100&limit=200")
+ assert response.status_code == 200
+ assert response.json() == {
+ "message": "Hello Items!",
+ "params": {"q": "foo", "skip": 5, "limit": 10},
+ }
diff --git a/docs_src/dependency_testing/tutorial001_an_py39.py b/docs_src/dependency_testing/tutorial001_an_py39.py
new file mode 100644
index 000000000..bccb0cdb1
--- /dev/null
+++ b/docs_src/dependency_testing/tutorial001_an_py39.py
@@ -0,0 +1,59 @@
+from typing import Annotated, Union
+
+from fastapi import Depends, FastAPI
+from fastapi.testclient import TestClient
+
+app = FastAPI()
+
+
+async def common_parameters(
+ q: Union[str, None] = None, skip: int = 0, limit: int = 100
+):
+ return {"q": q, "skip": skip, "limit": limit}
+
+
+@app.get("/items/")
+async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
+ return {"message": "Hello Items!", "params": commons}
+
+
+@app.get("/users/")
+async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
+ return {"message": "Hello Users!", "params": commons}
+
+
+client = TestClient(app)
+
+
+async def override_dependency(q: Union[str, None] = None):
+ return {"q": q, "skip": 5, "limit": 10}
+
+
+app.dependency_overrides[common_parameters] = override_dependency
+
+
+def test_override_in_items():
+ response = client.get("/items/")
+ assert response.status_code == 200
+ assert response.json() == {
+ "message": "Hello Items!",
+ "params": {"q": None, "skip": 5, "limit": 10},
+ }
+
+
+def test_override_in_items_with_q():
+ response = client.get("/items/?q=foo")
+ assert response.status_code == 200
+ assert response.json() == {
+ "message": "Hello Items!",
+ "params": {"q": "foo", "skip": 5, "limit": 10},
+ }
+
+
+def test_override_in_items_with_params():
+ response = client.get("/items/?q=foo&skip=100&limit=200")
+ assert response.status_code == 200
+ assert response.json() == {
+ "message": "Hello Items!",
+ "params": {"q": "foo", "skip": 5, "limit": 10},
+ }
diff --git a/docs_src/dependency_testing/tutorial001_py310.py b/docs_src/dependency_testing/tutorial001_py310.py
new file mode 100644
index 000000000..d1f6d4374
--- /dev/null
+++ b/docs_src/dependency_testing/tutorial001_py310.py
@@ -0,0 +1,55 @@
+from fastapi import Depends, FastAPI
+from fastapi.testclient import TestClient
+
+app = FastAPI()
+
+
+async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
+ return {"q": q, "skip": skip, "limit": limit}
+
+
+@app.get("/items/")
+async def read_items(commons: dict = Depends(common_parameters)):
+ return {"message": "Hello Items!", "params": commons}
+
+
+@app.get("/users/")
+async def read_users(commons: dict = Depends(common_parameters)):
+ return {"message": "Hello Users!", "params": commons}
+
+
+client = TestClient(app)
+
+
+async def override_dependency(q: str | None = None):
+ return {"q": q, "skip": 5, "limit": 10}
+
+
+app.dependency_overrides[common_parameters] = override_dependency
+
+
+def test_override_in_items():
+ response = client.get("/items/")
+ assert response.status_code == 200
+ assert response.json() == {
+ "message": "Hello Items!",
+ "params": {"q": None, "skip": 5, "limit": 10},
+ }
+
+
+def test_override_in_items_with_q():
+ response = client.get("/items/?q=foo")
+ assert response.status_code == 200
+ assert response.json() == {
+ "message": "Hello Items!",
+ "params": {"q": "foo", "skip": 5, "limit": 10},
+ }
+
+
+def test_override_in_items_with_params():
+ response = client.get("/items/?q=foo&skip=100&limit=200")
+ assert response.status_code == 200
+ assert response.json() == {
+ "message": "Hello Items!",
+ "params": {"q": "foo", "skip": 5, "limit": 10},
+ }
diff --git a/docs_src/events/tutorial003.py b/docs_src/events/tutorial003.py
new file mode 100644
index 000000000..2b650590b
--- /dev/null
+++ b/docs_src/events/tutorial003.py
@@ -0,0 +1,28 @@
+from contextlib import asynccontextmanager
+
+from fastapi import FastAPI
+
+
+def fake_answer_to_everything_ml_model(x: float):
+ return x * 42
+
+
+ml_models = {}
+
+
+@asynccontextmanager
+async def lifespan(app: FastAPI):
+ # Load the ML model
+ ml_models["answer_to_everything"] = fake_answer_to_everything_ml_model
+ yield
+ # Clean up the ML models and release the resources
+ ml_models.clear()
+
+
+app = FastAPI(lifespan=lifespan)
+
+
+@app.get("/predict")
+async def predict(x: float):
+ result = ml_models["answer_to_everything"](x)
+ return {"result": result}
diff --git a/docs_src/extra_data_types/tutorial001_an.py b/docs_src/extra_data_types/tutorial001_an.py
new file mode 100644
index 000000000..a4c074241
--- /dev/null
+++ b/docs_src/extra_data_types/tutorial001_an.py
@@ -0,0 +1,29 @@
+from datetime import datetime, time, timedelta
+from typing import Union
+from uuid import UUID
+
+from fastapi import Body, FastAPI
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.put("/items/{item_id}")
+async def read_items(
+ item_id: UUID,
+ start_datetime: Annotated[Union[datetime, None], Body()] = None,
+ end_datetime: Annotated[Union[datetime, None], Body()] = None,
+ repeat_at: Annotated[Union[time, None], Body()] = None,
+ process_after: Annotated[Union[timedelta, None], Body()] = None,
+):
+ start_process = start_datetime + process_after
+ duration = end_datetime - start_process
+ return {
+ "item_id": item_id,
+ "start_datetime": start_datetime,
+ "end_datetime": end_datetime,
+ "repeat_at": repeat_at,
+ "process_after": process_after,
+ "start_process": start_process,
+ "duration": duration,
+ }
diff --git a/docs_src/extra_data_types/tutorial001_an_py310.py b/docs_src/extra_data_types/tutorial001_an_py310.py
new file mode 100644
index 000000000..4f69c40d9
--- /dev/null
+++ b/docs_src/extra_data_types/tutorial001_an_py310.py
@@ -0,0 +1,28 @@
+from datetime import datetime, time, timedelta
+from typing import Annotated
+from uuid import UUID
+
+from fastapi import Body, FastAPI
+
+app = FastAPI()
+
+
+@app.put("/items/{item_id}")
+async def read_items(
+ item_id: UUID,
+ start_datetime: Annotated[datetime | None, Body()] = None,
+ end_datetime: Annotated[datetime | None, Body()] = None,
+ repeat_at: Annotated[time | None, Body()] = None,
+ process_after: Annotated[timedelta | None, Body()] = None,
+):
+ start_process = start_datetime + process_after
+ duration = end_datetime - start_process
+ return {
+ "item_id": item_id,
+ "start_datetime": start_datetime,
+ "end_datetime": end_datetime,
+ "repeat_at": repeat_at,
+ "process_after": process_after,
+ "start_process": start_process,
+ "duration": duration,
+ }
diff --git a/docs_src/extra_data_types/tutorial001_an_py39.py b/docs_src/extra_data_types/tutorial001_an_py39.py
new file mode 100644
index 000000000..630d36ae3
--- /dev/null
+++ b/docs_src/extra_data_types/tutorial001_an_py39.py
@@ -0,0 +1,28 @@
+from datetime import datetime, time, timedelta
+from typing import Annotated, Union
+from uuid import UUID
+
+from fastapi import Body, FastAPI
+
+app = FastAPI()
+
+
+@app.put("/items/{item_id}")
+async def read_items(
+ item_id: UUID,
+ start_datetime: Annotated[Union[datetime, None], Body()] = None,
+ end_datetime: Annotated[Union[datetime, None], Body()] = None,
+ repeat_at: Annotated[Union[time, None], Body()] = None,
+ process_after: Annotated[Union[timedelta, None], Body()] = None,
+):
+ start_process = start_datetime + process_after
+ duration = end_datetime - start_process
+ return {
+ "item_id": item_id,
+ "start_datetime": start_datetime,
+ "end_datetime": end_datetime,
+ "repeat_at": repeat_at,
+ "process_after": process_after,
+ "start_process": start_process,
+ "duration": duration,
+ }
diff --git a/docs_src/header_params/tutorial001_an.py b/docs_src/header_params/tutorial001_an.py
new file mode 100644
index 000000000..816c00086
--- /dev/null
+++ b/docs_src/header_params/tutorial001_an.py
@@ -0,0 +1,11 @@
+from typing import Union
+
+from fastapi import FastAPI, Header
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(user_agent: Annotated[Union[str, None], Header()] = None):
+ return {"User-Agent": user_agent}
diff --git a/docs_src/header_params/tutorial001_an_py310.py b/docs_src/header_params/tutorial001_an_py310.py
new file mode 100644
index 000000000..4ba5e1bfb
--- /dev/null
+++ b/docs_src/header_params/tutorial001_an_py310.py
@@ -0,0 +1,10 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Header
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(user_agent: Annotated[str | None, Header()] = None):
+ return {"User-Agent": user_agent}
diff --git a/docs_src/header_params/tutorial001_an_py39.py b/docs_src/header_params/tutorial001_an_py39.py
new file mode 100644
index 000000000..1fbe3bb99
--- /dev/null
+++ b/docs_src/header_params/tutorial001_an_py39.py
@@ -0,0 +1,10 @@
+from typing import Annotated, Union
+
+from fastapi import FastAPI, Header
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(user_agent: Annotated[Union[str, None], Header()] = None):
+ return {"User-Agent": user_agent}
diff --git a/docs_src/header_params/tutorial002_an.py b/docs_src/header_params/tutorial002_an.py
new file mode 100644
index 000000000..65d972d46
--- /dev/null
+++ b/docs_src/header_params/tutorial002_an.py
@@ -0,0 +1,15 @@
+from typing import Union
+
+from fastapi import FastAPI, Header
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ strange_header: Annotated[
+ Union[str, None], Header(convert_underscores=False)
+ ] = None
+):
+ return {"strange_header": strange_header}
diff --git a/docs_src/header_params/tutorial002_an_py310.py b/docs_src/header_params/tutorial002_an_py310.py
new file mode 100644
index 000000000..b340647b6
--- /dev/null
+++ b/docs_src/header_params/tutorial002_an_py310.py
@@ -0,0 +1,12 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Header
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ strange_header: Annotated[str | None, Header(convert_underscores=False)] = None
+):
+ return {"strange_header": strange_header}
diff --git a/docs_src/header_params/tutorial002_an_py39.py b/docs_src/header_params/tutorial002_an_py39.py
new file mode 100644
index 000000000..7f6a99f9c
--- /dev/null
+++ b/docs_src/header_params/tutorial002_an_py39.py
@@ -0,0 +1,14 @@
+from typing import Annotated, Union
+
+from fastapi import FastAPI, Header
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ strange_header: Annotated[
+ Union[str, None], Header(convert_underscores=False)
+ ] = None
+):
+ return {"strange_header": strange_header}
diff --git a/docs_src/header_params/tutorial003_an.py b/docs_src/header_params/tutorial003_an.py
new file mode 100644
index 000000000..5406fd1f8
--- /dev/null
+++ b/docs_src/header_params/tutorial003_an.py
@@ -0,0 +1,11 @@
+from typing import List, Union
+
+from fastapi import FastAPI, Header
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(x_token: Annotated[Union[List[str], None], Header()] = None):
+ return {"X-Token values": x_token}
diff --git a/docs_src/header_params/tutorial003_an_py310.py b/docs_src/header_params/tutorial003_an_py310.py
new file mode 100644
index 000000000..0e78cf029
--- /dev/null
+++ b/docs_src/header_params/tutorial003_an_py310.py
@@ -0,0 +1,10 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Header
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(x_token: Annotated[list[str] | None, Header()] = None):
+ return {"X-Token values": x_token}
diff --git a/docs_src/header_params/tutorial003_an_py39.py b/docs_src/header_params/tutorial003_an_py39.py
new file mode 100644
index 000000000..c1dd49961
--- /dev/null
+++ b/docs_src/header_params/tutorial003_an_py39.py
@@ -0,0 +1,10 @@
+from typing import Annotated, List, Union
+
+from fastapi import FastAPI, Header
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(x_token: Annotated[Union[List[str], None], Header()] = None):
+ return {"X-Token values": x_token}
diff --git a/docs_src/path_params_numeric_validations/tutorial001_an.py b/docs_src/path_params_numeric_validations/tutorial001_an.py
new file mode 100644
index 000000000..621be7b04
--- /dev/null
+++ b/docs_src/path_params_numeric_validations/tutorial001_an.py
@@ -0,0 +1,17 @@
+from typing import Union
+
+from fastapi import FastAPI, Path, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/{item_id}")
+async def read_items(
+ item_id: Annotated[int, Path(title="The ID of the item to get")],
+ q: Annotated[Union[str, None], Query(alias="item-query")] = None,
+):
+ results = {"item_id": item_id}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/path_params_numeric_validations/tutorial001_an_py310.py b/docs_src/path_params_numeric_validations/tutorial001_an_py310.py
new file mode 100644
index 000000000..c4db263f0
--- /dev/null
+++ b/docs_src/path_params_numeric_validations/tutorial001_an_py310.py
@@ -0,0 +1,16 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Path, Query
+
+app = FastAPI()
+
+
+@app.get("/items/{item_id}")
+async def read_items(
+ item_id: Annotated[int, Path(title="The ID of the item to get")],
+ q: Annotated[str | None, Query(alias="item-query")] = None,
+):
+ results = {"item_id": item_id}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/path_params_numeric_validations/tutorial001_an_py39.py b/docs_src/path_params_numeric_validations/tutorial001_an_py39.py
new file mode 100644
index 000000000..b36315a46
--- /dev/null
+++ b/docs_src/path_params_numeric_validations/tutorial001_an_py39.py
@@ -0,0 +1,16 @@
+from typing import Annotated, Union
+
+from fastapi import FastAPI, Path, Query
+
+app = FastAPI()
+
+
+@app.get("/items/{item_id}")
+async def read_items(
+ item_id: Annotated[int, Path(title="The ID of the item to get")],
+ q: Annotated[Union[str, None], Query(alias="item-query")] = None,
+):
+ results = {"item_id": item_id}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/path_params_numeric_validations/tutorial002_an.py b/docs_src/path_params_numeric_validations/tutorial002_an.py
new file mode 100644
index 000000000..322f8cf0b
--- /dev/null
+++ b/docs_src/path_params_numeric_validations/tutorial002_an.py
@@ -0,0 +1,14 @@
+from fastapi import FastAPI, Path
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/{item_id}")
+async def read_items(
+ q: str, item_id: Annotated[int, Path(title="The ID of the item to get")]
+):
+ results = {"item_id": item_id}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/path_params_numeric_validations/tutorial002_an_py39.py b/docs_src/path_params_numeric_validations/tutorial002_an_py39.py
new file mode 100644
index 000000000..cd882abb2
--- /dev/null
+++ b/docs_src/path_params_numeric_validations/tutorial002_an_py39.py
@@ -0,0 +1,15 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Path
+
+app = FastAPI()
+
+
+@app.get("/items/{item_id}")
+async def read_items(
+ q: str, item_id: Annotated[int, Path(title="The ID of the item to get")]
+):
+ results = {"item_id": item_id}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/path_params_numeric_validations/tutorial003_an.py b/docs_src/path_params_numeric_validations/tutorial003_an.py
new file mode 100644
index 000000000..d0fa8b3db
--- /dev/null
+++ b/docs_src/path_params_numeric_validations/tutorial003_an.py
@@ -0,0 +1,14 @@
+from fastapi import FastAPI, Path
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/{item_id}")
+async def read_items(
+ item_id: Annotated[int, Path(title="The ID of the item to get")], q: str
+):
+ results = {"item_id": item_id}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/path_params_numeric_validations/tutorial003_an_py39.py b/docs_src/path_params_numeric_validations/tutorial003_an_py39.py
new file mode 100644
index 000000000..1588556e7
--- /dev/null
+++ b/docs_src/path_params_numeric_validations/tutorial003_an_py39.py
@@ -0,0 +1,15 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Path
+
+app = FastAPI()
+
+
+@app.get("/items/{item_id}")
+async def read_items(
+ item_id: Annotated[int, Path(title="The ID of the item to get")], q: str
+):
+ results = {"item_id": item_id}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/path_params_numeric_validations/tutorial004_an.py b/docs_src/path_params_numeric_validations/tutorial004_an.py
new file mode 100644
index 000000000..ffc50f6c5
--- /dev/null
+++ b/docs_src/path_params_numeric_validations/tutorial004_an.py
@@ -0,0 +1,14 @@
+from fastapi import FastAPI, Path
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/{item_id}")
+async def read_items(
+ item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)], q: str
+):
+ results = {"item_id": item_id}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/path_params_numeric_validations/tutorial004_an_py39.py b/docs_src/path_params_numeric_validations/tutorial004_an_py39.py
new file mode 100644
index 000000000..f67f6450e
--- /dev/null
+++ b/docs_src/path_params_numeric_validations/tutorial004_an_py39.py
@@ -0,0 +1,15 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Path
+
+app = FastAPI()
+
+
+@app.get("/items/{item_id}")
+async def read_items(
+ item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)], q: str
+):
+ results = {"item_id": item_id}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/path_params_numeric_validations/tutorial005_an.py b/docs_src/path_params_numeric_validations/tutorial005_an.py
new file mode 100644
index 000000000..433c69129
--- /dev/null
+++ b/docs_src/path_params_numeric_validations/tutorial005_an.py
@@ -0,0 +1,15 @@
+from fastapi import FastAPI, Path
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/{item_id}")
+async def read_items(
+ item_id: Annotated[int, Path(title="The ID of the item to get", gt=0, le=1000)],
+ q: str,
+):
+ results = {"item_id": item_id}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/path_params_numeric_validations/tutorial005_an_py39.py b/docs_src/path_params_numeric_validations/tutorial005_an_py39.py
new file mode 100644
index 000000000..571dd583c
--- /dev/null
+++ b/docs_src/path_params_numeric_validations/tutorial005_an_py39.py
@@ -0,0 +1,16 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Path
+
+app = FastAPI()
+
+
+@app.get("/items/{item_id}")
+async def read_items(
+ item_id: Annotated[int, Path(title="The ID of the item to get", gt=0, le=1000)],
+ q: str,
+):
+ results = {"item_id": item_id}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/path_params_numeric_validations/tutorial006.py b/docs_src/path_params_numeric_validations/tutorial006.py
index 85bd6e8b4..0ea32694a 100644
--- a/docs_src/path_params_numeric_validations/tutorial006.py
+++ b/docs_src/path_params_numeric_validations/tutorial006.py
@@ -8,7 +8,7 @@ async def read_items(
*,
item_id: int = Path(title="The ID of the item to get", ge=0, le=1000),
q: str,
- size: float = Query(gt=0, lt=10.5)
+ size: float = Query(gt=0, lt=10.5),
):
results = {"item_id": item_id}
if q:
diff --git a/docs_src/path_params_numeric_validations/tutorial006_an.py b/docs_src/path_params_numeric_validations/tutorial006_an.py
new file mode 100644
index 000000000..22a143623
--- /dev/null
+++ b/docs_src/path_params_numeric_validations/tutorial006_an.py
@@ -0,0 +1,17 @@
+from fastapi import FastAPI, Path, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/{item_id}")
+async def read_items(
+ *,
+ item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
+ q: str,
+ size: Annotated[float, Query(gt=0, lt=10.5)],
+):
+ results = {"item_id": item_id}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/path_params_numeric_validations/tutorial006_an_py39.py b/docs_src/path_params_numeric_validations/tutorial006_an_py39.py
new file mode 100644
index 000000000..804751893
--- /dev/null
+++ b/docs_src/path_params_numeric_validations/tutorial006_an_py39.py
@@ -0,0 +1,18 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Path, Query
+
+app = FastAPI()
+
+
+@app.get("/items/{item_id}")
+async def read_items(
+ *,
+ item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
+ q: str,
+ size: Annotated[float, Query(gt=0, lt=10.5)],
+):
+ results = {"item_id": item_id}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/python_types/tutorial013.py b/docs_src/python_types/tutorial013.py
new file mode 100644
index 000000000..0ec773519
--- /dev/null
+++ b/docs_src/python_types/tutorial013.py
@@ -0,0 +1,5 @@
+from typing_extensions import Annotated
+
+
+def say_hello(name: Annotated[str, "this is just metadata"]) -> str:
+ return f"Hello {name}"
diff --git a/docs_src/python_types/tutorial013_py39.py b/docs_src/python_types/tutorial013_py39.py
new file mode 100644
index 000000000..65a0eaa93
--- /dev/null
+++ b/docs_src/python_types/tutorial013_py39.py
@@ -0,0 +1,5 @@
+from typing import Annotated
+
+
+def say_hello(name: Annotated[str, "this is just metadata"]) -> str:
+ return f"Hello {name}"
diff --git a/docs_src/query_params_str_validations/tutorial002_an.py b/docs_src/query_params_str_validations/tutorial002_an.py
new file mode 100644
index 000000000..cb1b38940
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial002_an.py
@@ -0,0 +1,14 @@
+from typing import Union
+
+from fastapi import FastAPI, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[Union[str, None], Query(max_length=50)] = None):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial002_an_py310.py b/docs_src/query_params_str_validations/tutorial002_an_py310.py
new file mode 100644
index 000000000..66ee7451b
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial002_an_py310.py
@@ -0,0 +1,13 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[str | None, Query(max_length=50)] = None):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial003_an.py b/docs_src/query_params_str_validations/tutorial003_an.py
new file mode 100644
index 000000000..a3665f6a8
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial003_an.py
@@ -0,0 +1,16 @@
+from typing import Union
+
+from fastapi import FastAPI, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ q: Annotated[Union[str, None], Query(min_length=3, max_length=50)] = None
+):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial003_an_py310.py b/docs_src/query_params_str_validations/tutorial003_an_py310.py
new file mode 100644
index 000000000..836af04de
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial003_an_py310.py
@@ -0,0 +1,15 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ q: Annotated[str | None, Query(min_length=3, max_length=50)] = None
+):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial003_an_py39.py b/docs_src/query_params_str_validations/tutorial003_an_py39.py
new file mode 100644
index 000000000..87a426839
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial003_an_py39.py
@@ -0,0 +1,15 @@
+from typing import Annotated, Union
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ q: Annotated[Union[str, None], Query(min_length=3, max_length=50)] = None
+):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial004_an.py b/docs_src/query_params_str_validations/tutorial004_an.py
new file mode 100644
index 000000000..5346b997b
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial004_an.py
@@ -0,0 +1,18 @@
+from typing import Union
+
+from fastapi import FastAPI, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ q: Annotated[
+ Union[str, None], Query(min_length=3, max_length=50, regex="^fixedquery$")
+ ] = None
+):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial004_an_py310.py b/docs_src/query_params_str_validations/tutorial004_an_py310.py
new file mode 100644
index 000000000..8fd375b3d
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial004_an_py310.py
@@ -0,0 +1,17 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ q: Annotated[
+ str | None, Query(min_length=3, max_length=50, regex="^fixedquery$")
+ ] = None
+):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial004_an_py39.py b/docs_src/query_params_str_validations/tutorial004_an_py39.py
new file mode 100644
index 000000000..2fd82db75
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial004_an_py39.py
@@ -0,0 +1,17 @@
+from typing import Annotated, Union
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ q: Annotated[
+ Union[str, None], Query(min_length=3, max_length=50, regex="^fixedquery$")
+ ] = None
+):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial005_an.py b/docs_src/query_params_str_validations/tutorial005_an.py
new file mode 100644
index 000000000..452d4d38d
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial005_an.py
@@ -0,0 +1,12 @@
+from fastapi import FastAPI, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[str, Query(min_length=3)] = "fixedquery"):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial005_an_py39.py b/docs_src/query_params_str_validations/tutorial005_an_py39.py
new file mode 100644
index 000000000..b1f6046b5
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial005_an_py39.py
@@ -0,0 +1,13 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[str, Query(min_length=3)] = "fixedquery"):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial006_an.py b/docs_src/query_params_str_validations/tutorial006_an.py
new file mode 100644
index 000000000..559480d2b
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial006_an.py
@@ -0,0 +1,12 @@
+from fastapi import FastAPI, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[str, Query(min_length=3)]):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial006_an_py39.py b/docs_src/query_params_str_validations/tutorial006_an_py39.py
new file mode 100644
index 000000000..3b4a676d2
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial006_an_py39.py
@@ -0,0 +1,13 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[str, Query(min_length=3)]):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial006b_an.py b/docs_src/query_params_str_validations/tutorial006b_an.py
new file mode 100644
index 000000000..ea3b02583
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial006b_an.py
@@ -0,0 +1,12 @@
+from fastapi import FastAPI, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[str, Query(min_length=3)] = ...):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial006b_an_py39.py b/docs_src/query_params_str_validations/tutorial006b_an_py39.py
new file mode 100644
index 000000000..687a9f544
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial006b_an_py39.py
@@ -0,0 +1,13 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[str, Query(min_length=3)] = ...):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial006c_an.py b/docs_src/query_params_str_validations/tutorial006c_an.py
new file mode 100644
index 000000000..10bf26a57
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial006c_an.py
@@ -0,0 +1,14 @@
+from typing import Union
+
+from fastapi import FastAPI, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[Union[str, None], Query(min_length=3)] = ...):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial006c_an_py310.py b/docs_src/query_params_str_validations/tutorial006c_an_py310.py
new file mode 100644
index 000000000..1ab0a7d53
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial006c_an_py310.py
@@ -0,0 +1,13 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[str | None, Query(min_length=3)] = ...):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial006c_an_py39.py b/docs_src/query_params_str_validations/tutorial006c_an_py39.py
new file mode 100644
index 000000000..ac1273331
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial006c_an_py39.py
@@ -0,0 +1,13 @@
+from typing import Annotated, Union
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[Union[str, None], Query(min_length=3)] = ...):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial006d_an.py b/docs_src/query_params_str_validations/tutorial006d_an.py
new file mode 100644
index 000000000..bc8283e15
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial006d_an.py
@@ -0,0 +1,13 @@
+from fastapi import FastAPI, Query
+from pydantic import Required
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[str, Query(min_length=3)] = Required):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial006d_an_py39.py b/docs_src/query_params_str_validations/tutorial006d_an_py39.py
new file mode 100644
index 000000000..035d9e3bd
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial006d_an_py39.py
@@ -0,0 +1,14 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Query
+from pydantic import Required
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[str, Query(min_length=3)] = Required):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial007_an.py b/docs_src/query_params_str_validations/tutorial007_an.py
new file mode 100644
index 000000000..3bc85cc0c
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial007_an.py
@@ -0,0 +1,16 @@
+from typing import Union
+
+from fastapi import FastAPI, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ q: Annotated[Union[str, None], Query(title="Query string", min_length=3)] = None
+):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial007_an_py310.py b/docs_src/query_params_str_validations/tutorial007_an_py310.py
new file mode 100644
index 000000000..5933911fd
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial007_an_py310.py
@@ -0,0 +1,15 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ q: Annotated[str | None, Query(title="Query string", min_length=3)] = None
+):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial007_an_py39.py b/docs_src/query_params_str_validations/tutorial007_an_py39.py
new file mode 100644
index 000000000..dafa1c5c9
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial007_an_py39.py
@@ -0,0 +1,15 @@
+from typing import Annotated, Union
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ q: Annotated[Union[str, None], Query(title="Query string", min_length=3)] = None
+):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial008_an.py b/docs_src/query_params_str_validations/tutorial008_an.py
new file mode 100644
index 000000000..5699f1e88
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial008_an.py
@@ -0,0 +1,23 @@
+from typing import Union
+
+from fastapi import FastAPI, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ q: Annotated[
+ Union[str, None],
+ Query(
+ title="Query string",
+ description="Query string for the items to search in the database that have a good match",
+ min_length=3,
+ ),
+ ] = None
+):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial008_an_py310.py b/docs_src/query_params_str_validations/tutorial008_an_py310.py
new file mode 100644
index 000000000..4aaadf8b4
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial008_an_py310.py
@@ -0,0 +1,22 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ q: Annotated[
+ str | None,
+ Query(
+ title="Query string",
+ description="Query string for the items to search in the database that have a good match",
+ min_length=3,
+ ),
+ ] = None
+):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial008_an_py39.py b/docs_src/query_params_str_validations/tutorial008_an_py39.py
new file mode 100644
index 000000000..1c3b36176
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial008_an_py39.py
@@ -0,0 +1,22 @@
+from typing import Annotated, Union
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ q: Annotated[
+ Union[str, None],
+ Query(
+ title="Query string",
+ description="Query string for the items to search in the database that have a good match",
+ min_length=3,
+ ),
+ ] = None
+):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial009_an.py b/docs_src/query_params_str_validations/tutorial009_an.py
new file mode 100644
index 000000000..2894e2d51
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial009_an.py
@@ -0,0 +1,14 @@
+from typing import Union
+
+from fastapi import FastAPI, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[Union[str, None], Query(alias="item-query")] = None):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial009_an_py310.py b/docs_src/query_params_str_validations/tutorial009_an_py310.py
new file mode 100644
index 000000000..d11753362
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial009_an_py310.py
@@ -0,0 +1,13 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[str | None, Query(alias="item-query")] = None):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial009_an_py39.py b/docs_src/query_params_str_validations/tutorial009_an_py39.py
new file mode 100644
index 000000000..70a89e613
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial009_an_py39.py
@@ -0,0 +1,13 @@
+from typing import Annotated, Union
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[Union[str, None], Query(alias="item-query")] = None):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial010_an.py b/docs_src/query_params_str_validations/tutorial010_an.py
new file mode 100644
index 000000000..8995f3f57
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial010_an.py
@@ -0,0 +1,27 @@
+from typing import Union
+
+from fastapi import FastAPI, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ q: Annotated[
+ Union[str, None],
+ Query(
+ alias="item-query",
+ title="Query string",
+ description="Query string for the items to search in the database that have a good match",
+ min_length=3,
+ max_length=50,
+ regex="^fixedquery$",
+ deprecated=True,
+ ),
+ ] = None
+):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial010_an_py310.py b/docs_src/query_params_str_validations/tutorial010_an_py310.py
new file mode 100644
index 000000000..cfa81926c
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial010_an_py310.py
@@ -0,0 +1,26 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ q: Annotated[
+ str | None,
+ Query(
+ alias="item-query",
+ title="Query string",
+ description="Query string for the items to search in the database that have a good match",
+ min_length=3,
+ max_length=50,
+ regex="^fixedquery$",
+ deprecated=True,
+ ),
+ ] = None
+):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial010_an_py39.py b/docs_src/query_params_str_validations/tutorial010_an_py39.py
new file mode 100644
index 000000000..220eaabf4
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial010_an_py39.py
@@ -0,0 +1,26 @@
+from typing import Annotated, Union
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ q: Annotated[
+ Union[str, None],
+ Query(
+ alias="item-query",
+ title="Query string",
+ description="Query string for the items to search in the database that have a good match",
+ min_length=3,
+ max_length=50,
+ regex="^fixedquery$",
+ deprecated=True,
+ ),
+ ] = None
+):
+ results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
+ if q:
+ results.update({"q": q})
+ return results
diff --git a/docs_src/query_params_str_validations/tutorial011_an.py b/docs_src/query_params_str_validations/tutorial011_an.py
new file mode 100644
index 000000000..8ed699337
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial011_an.py
@@ -0,0 +1,12 @@
+from typing import List, Union
+
+from fastapi import FastAPI, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[Union[List[str], None], Query()] = None):
+ query_items = {"q": q}
+ return query_items
diff --git a/docs_src/query_params_str_validations/tutorial011_an_py310.py b/docs_src/query_params_str_validations/tutorial011_an_py310.py
new file mode 100644
index 000000000..5dad4bfde
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial011_an_py310.py
@@ -0,0 +1,11 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[list[str] | None, Query()] = None):
+ query_items = {"q": q}
+ return query_items
diff --git a/docs_src/query_params_str_validations/tutorial011_an_py39.py b/docs_src/query_params_str_validations/tutorial011_an_py39.py
new file mode 100644
index 000000000..416e3990d
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial011_an_py39.py
@@ -0,0 +1,11 @@
+from typing import Annotated, Union
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[Union[list[str], None], Query()] = None):
+ query_items = {"q": q}
+ return query_items
diff --git a/docs_src/query_params_str_validations/tutorial012_an.py b/docs_src/query_params_str_validations/tutorial012_an.py
new file mode 100644
index 000000000..261af250a
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial012_an.py
@@ -0,0 +1,12 @@
+from typing import List
+
+from fastapi import FastAPI, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[List[str], Query()] = ["foo", "bar"]):
+ query_items = {"q": q}
+ return query_items
diff --git a/docs_src/query_params_str_validations/tutorial012_an_py39.py b/docs_src/query_params_str_validations/tutorial012_an_py39.py
new file mode 100644
index 000000000..9b5a9c2fb
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial012_an_py39.py
@@ -0,0 +1,11 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[list[str], Query()] = ["foo", "bar"]):
+ query_items = {"q": q}
+ return query_items
diff --git a/docs_src/query_params_str_validations/tutorial013_an.py b/docs_src/query_params_str_validations/tutorial013_an.py
new file mode 100644
index 000000000..f12a25055
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial013_an.py
@@ -0,0 +1,10 @@
+from fastapi import FastAPI, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[list, Query()] = []):
+ query_items = {"q": q}
+ return query_items
diff --git a/docs_src/query_params_str_validations/tutorial013_an_py39.py b/docs_src/query_params_str_validations/tutorial013_an_py39.py
new file mode 100644
index 000000000..602734145
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial013_an_py39.py
@@ -0,0 +1,11 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(q: Annotated[list, Query()] = []):
+ query_items = {"q": q}
+ return query_items
diff --git a/docs_src/query_params_str_validations/tutorial014_an.py b/docs_src/query_params_str_validations/tutorial014_an.py
new file mode 100644
index 000000000..a9a9c4427
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial014_an.py
@@ -0,0 +1,16 @@
+from typing import Union
+
+from fastapi import FastAPI, Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ hidden_query: Annotated[Union[str, None], Query(include_in_schema=False)] = None
+):
+ if hidden_query:
+ return {"hidden_query": hidden_query}
+ else:
+ return {"hidden_query": "Not found"}
diff --git a/docs_src/query_params_str_validations/tutorial014_an_py310.py b/docs_src/query_params_str_validations/tutorial014_an_py310.py
new file mode 100644
index 000000000..5fba54150
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial014_an_py310.py
@@ -0,0 +1,15 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ hidden_query: Annotated[str | None, Query(include_in_schema=False)] = None
+):
+ if hidden_query:
+ return {"hidden_query": hidden_query}
+ else:
+ return {"hidden_query": "Not found"}
diff --git a/docs_src/query_params_str_validations/tutorial014_an_py39.py b/docs_src/query_params_str_validations/tutorial014_an_py39.py
new file mode 100644
index 000000000..b07985210
--- /dev/null
+++ b/docs_src/query_params_str_validations/tutorial014_an_py39.py
@@ -0,0 +1,15 @@
+from typing import Annotated, Union
+
+from fastapi import FastAPI, Query
+
+app = FastAPI()
+
+
+@app.get("/items/")
+async def read_items(
+ hidden_query: Annotated[Union[str, None], Query(include_in_schema=False)] = None
+):
+ if hidden_query:
+ return {"hidden_query": hidden_query}
+ else:
+ return {"hidden_query": "Not found"}
diff --git a/docs_src/request_files/tutorial001_02_an.py b/docs_src/request_files/tutorial001_02_an.py
new file mode 100644
index 000000000..5007fef15
--- /dev/null
+++ b/docs_src/request_files/tutorial001_02_an.py
@@ -0,0 +1,22 @@
+from typing import Union
+
+from fastapi import FastAPI, File, UploadFile
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.post("/files/")
+async def create_file(file: Annotated[Union[bytes, None], File()] = None):
+ if not file:
+ return {"message": "No file sent"}
+ else:
+ return {"file_size": len(file)}
+
+
+@app.post("/uploadfile/")
+async def create_upload_file(file: Union[UploadFile, None] = None):
+ if not file:
+ return {"message": "No upload file sent"}
+ else:
+ return {"filename": file.filename}
diff --git a/docs_src/request_files/tutorial001_02_an_py310.py b/docs_src/request_files/tutorial001_02_an_py310.py
new file mode 100644
index 000000000..9b80321b4
--- /dev/null
+++ b/docs_src/request_files/tutorial001_02_an_py310.py
@@ -0,0 +1,21 @@
+from typing import Annotated
+
+from fastapi import FastAPI, File, UploadFile
+
+app = FastAPI()
+
+
+@app.post("/files/")
+async def create_file(file: Annotated[bytes | None, File()] = None):
+ if not file:
+ return {"message": "No file sent"}
+ else:
+ return {"file_size": len(file)}
+
+
+@app.post("/uploadfile/")
+async def create_upload_file(file: UploadFile | None = None):
+ if not file:
+ return {"message": "No upload file sent"}
+ else:
+ return {"filename": file.filename}
diff --git a/docs_src/request_files/tutorial001_02_an_py39.py b/docs_src/request_files/tutorial001_02_an_py39.py
new file mode 100644
index 000000000..bb090ff6c
--- /dev/null
+++ b/docs_src/request_files/tutorial001_02_an_py39.py
@@ -0,0 +1,21 @@
+from typing import Annotated, Union
+
+from fastapi import FastAPI, File, UploadFile
+
+app = FastAPI()
+
+
+@app.post("/files/")
+async def create_file(file: Annotated[Union[bytes, None], File()] = None):
+ if not file:
+ return {"message": "No file sent"}
+ else:
+ return {"file_size": len(file)}
+
+
+@app.post("/uploadfile/")
+async def create_upload_file(file: Union[UploadFile, None] = None):
+ if not file:
+ return {"message": "No upload file sent"}
+ else:
+ return {"filename": file.filename}
diff --git a/docs_src/request_files/tutorial001_03_an.py b/docs_src/request_files/tutorial001_03_an.py
new file mode 100644
index 000000000..8a6b0a245
--- /dev/null
+++ b/docs_src/request_files/tutorial001_03_an.py
@@ -0,0 +1,16 @@
+from fastapi import FastAPI, File, UploadFile
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.post("/files/")
+async def create_file(file: Annotated[bytes, File(description="A file read as bytes")]):
+ return {"file_size": len(file)}
+
+
+@app.post("/uploadfile/")
+async def create_upload_file(
+ file: Annotated[UploadFile, File(description="A file read as UploadFile")],
+):
+ return {"filename": file.filename}
diff --git a/docs_src/request_files/tutorial001_03_an_py39.py b/docs_src/request_files/tutorial001_03_an_py39.py
new file mode 100644
index 000000000..93098a677
--- /dev/null
+++ b/docs_src/request_files/tutorial001_03_an_py39.py
@@ -0,0 +1,17 @@
+from typing import Annotated
+
+from fastapi import FastAPI, File, UploadFile
+
+app = FastAPI()
+
+
+@app.post("/files/")
+async def create_file(file: Annotated[bytes, File(description="A file read as bytes")]):
+ return {"file_size": len(file)}
+
+
+@app.post("/uploadfile/")
+async def create_upload_file(
+ file: Annotated[UploadFile, File(description="A file read as UploadFile")],
+):
+ return {"filename": file.filename}
diff --git a/docs_src/request_files/tutorial001_an.py b/docs_src/request_files/tutorial001_an.py
new file mode 100644
index 000000000..ca2f76d5c
--- /dev/null
+++ b/docs_src/request_files/tutorial001_an.py
@@ -0,0 +1,14 @@
+from fastapi import FastAPI, File, UploadFile
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.post("/files/")
+async def create_file(file: Annotated[bytes, File()]):
+ return {"file_size": len(file)}
+
+
+@app.post("/uploadfile/")
+async def create_upload_file(file: UploadFile):
+ return {"filename": file.filename}
diff --git a/docs_src/request_files/tutorial001_an_py39.py b/docs_src/request_files/tutorial001_an_py39.py
new file mode 100644
index 000000000..26a767221
--- /dev/null
+++ b/docs_src/request_files/tutorial001_an_py39.py
@@ -0,0 +1,15 @@
+from typing import Annotated
+
+from fastapi import FastAPI, File, UploadFile
+
+app = FastAPI()
+
+
+@app.post("/files/")
+async def create_file(file: Annotated[bytes, File()]):
+ return {"file_size": len(file)}
+
+
+@app.post("/uploadfile/")
+async def create_upload_file(file: UploadFile):
+ return {"filename": file.filename}
diff --git a/docs_src/request_files/tutorial002_an.py b/docs_src/request_files/tutorial002_an.py
new file mode 100644
index 000000000..eaa90da2b
--- /dev/null
+++ b/docs_src/request_files/tutorial002_an.py
@@ -0,0 +1,34 @@
+from typing import List
+
+from fastapi import FastAPI, File, UploadFile
+from fastapi.responses import HTMLResponse
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.post("/files/")
+async def create_files(files: Annotated[List[bytes], File()]):
+ return {"file_sizes": [len(file) for file in files]}
+
+
+@app.post("/uploadfiles/")
+async def create_upload_files(files: List[UploadFile]):
+ return {"filenames": [file.filename for file in files]}
+
+
+@app.get("/")
+async def main():
+ content = """
+
+
+
+
+ """
+ return HTMLResponse(content=content)
diff --git a/docs_src/request_files/tutorial002_an_py39.py b/docs_src/request_files/tutorial002_an_py39.py
new file mode 100644
index 000000000..db524ceab
--- /dev/null
+++ b/docs_src/request_files/tutorial002_an_py39.py
@@ -0,0 +1,33 @@
+from typing import Annotated
+
+from fastapi import FastAPI, File, UploadFile
+from fastapi.responses import HTMLResponse
+
+app = FastAPI()
+
+
+@app.post("/files/")
+async def create_files(files: Annotated[list[bytes], File()]):
+ return {"file_sizes": [len(file) for file in files]}
+
+
+@app.post("/uploadfiles/")
+async def create_upload_files(files: list[UploadFile]):
+ return {"filenames": [file.filename for file in files]}
+
+
+@app.get("/")
+async def main():
+ content = """
+
+
+
+
+ """
+ return HTMLResponse(content=content)
diff --git a/docs_src/request_files/tutorial003_an.py b/docs_src/request_files/tutorial003_an.py
new file mode 100644
index 000000000..2238e3c94
--- /dev/null
+++ b/docs_src/request_files/tutorial003_an.py
@@ -0,0 +1,40 @@
+from typing import List
+
+from fastapi import FastAPI, File, UploadFile
+from fastapi.responses import HTMLResponse
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.post("/files/")
+async def create_files(
+ files: Annotated[List[bytes], File(description="Multiple files as bytes")],
+):
+ return {"file_sizes": [len(file) for file in files]}
+
+
+@app.post("/uploadfiles/")
+async def create_upload_files(
+ files: Annotated[
+ List[UploadFile], File(description="Multiple files as UploadFile")
+ ],
+):
+ return {"filenames": [file.filename for file in files]}
+
+
+@app.get("/")
+async def main():
+ content = """
+
+
+
+
+ """
+ return HTMLResponse(content=content)
diff --git a/docs_src/request_files/tutorial003_an_py39.py b/docs_src/request_files/tutorial003_an_py39.py
new file mode 100644
index 000000000..5a8c5dab5
--- /dev/null
+++ b/docs_src/request_files/tutorial003_an_py39.py
@@ -0,0 +1,39 @@
+from typing import Annotated
+
+from fastapi import FastAPI, File, UploadFile
+from fastapi.responses import HTMLResponse
+
+app = FastAPI()
+
+
+@app.post("/files/")
+async def create_files(
+ files: Annotated[list[bytes], File(description="Multiple files as bytes")],
+):
+ return {"file_sizes": [len(file) for file in files]}
+
+
+@app.post("/uploadfiles/")
+async def create_upload_files(
+ files: Annotated[
+ list[UploadFile], File(description="Multiple files as UploadFile")
+ ],
+):
+ return {"filenames": [file.filename for file in files]}
+
+
+@app.get("/")
+async def main():
+ content = """
+
+
+
+
+ """
+ return HTMLResponse(content=content)
diff --git a/docs_src/request_forms/tutorial001_an.py b/docs_src/request_forms/tutorial001_an.py
new file mode 100644
index 000000000..677fbf2db
--- /dev/null
+++ b/docs_src/request_forms/tutorial001_an.py
@@ -0,0 +1,9 @@
+from fastapi import FastAPI, Form
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.post("/login/")
+async def login(username: Annotated[str, Form()], password: Annotated[str, Form()]):
+ return {"username": username}
diff --git a/docs_src/request_forms/tutorial001_an_py39.py b/docs_src/request_forms/tutorial001_an_py39.py
new file mode 100644
index 000000000..8e9d2ea53
--- /dev/null
+++ b/docs_src/request_forms/tutorial001_an_py39.py
@@ -0,0 +1,10 @@
+from typing import Annotated
+
+from fastapi import FastAPI, Form
+
+app = FastAPI()
+
+
+@app.post("/login/")
+async def login(username: Annotated[str, Form()], password: Annotated[str, Form()]):
+ return {"username": username}
diff --git a/docs_src/request_forms_and_files/tutorial001_an.py b/docs_src/request_forms_and_files/tutorial001_an.py
new file mode 100644
index 000000000..0ea285ac8
--- /dev/null
+++ b/docs_src/request_forms_and_files/tutorial001_an.py
@@ -0,0 +1,17 @@
+from fastapi import FastAPI, File, Form, UploadFile
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.post("/files/")
+async def create_file(
+ file: Annotated[bytes, File()],
+ fileb: Annotated[UploadFile, File()],
+ token: Annotated[str, Form()],
+):
+ return {
+ "file_size": len(file),
+ "token": token,
+ "fileb_content_type": fileb.content_type,
+ }
diff --git a/docs_src/request_forms_and_files/tutorial001_an_py39.py b/docs_src/request_forms_and_files/tutorial001_an_py39.py
new file mode 100644
index 000000000..12cc43e50
--- /dev/null
+++ b/docs_src/request_forms_and_files/tutorial001_an_py39.py
@@ -0,0 +1,18 @@
+from typing import Annotated
+
+from fastapi import FastAPI, File, Form, UploadFile
+
+app = FastAPI()
+
+
+@app.post("/files/")
+async def create_file(
+ file: Annotated[bytes, File()],
+ fileb: Annotated[UploadFile, File()],
+ token: Annotated[str, Form()],
+):
+ return {
+ "file_size": len(file),
+ "token": token,
+ "fileb_content_type": fileb.content_type,
+ }
diff --git a/docs_src/response_model/tutorial001.py b/docs_src/response_model/tutorial001.py
index 0f6e03e5b..fd1c902a5 100644
--- a/docs_src/response_model/tutorial001.py
+++ b/docs_src/response_model/tutorial001.py
@@ -1,4 +1,4 @@
-from typing import List, Union
+from typing import Any, List, Union
from fastapi import FastAPI
from pydantic import BaseModel
@@ -15,5 +15,13 @@ class Item(BaseModel):
@app.post("/items/", response_model=Item)
-async def create_item(item: Item):
+async def create_item(item: Item) -> Any:
return item
+
+
+@app.get("/items/", response_model=List[Item])
+async def read_items() -> Any:
+ return [
+ {"name": "Portal Gun", "price": 42.0},
+ {"name": "Plumbus", "price": 32.0},
+ ]
diff --git a/docs_src/response_model/tutorial001_01.py b/docs_src/response_model/tutorial001_01.py
new file mode 100644
index 000000000..98d30d540
--- /dev/null
+++ b/docs_src/response_model/tutorial001_01.py
@@ -0,0 +1,27 @@
+from typing import List, Union
+
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+ tags: List[str] = []
+
+
+@app.post("/items/")
+async def create_item(item: Item) -> Item:
+ return item
+
+
+@app.get("/items/")
+async def read_items() -> List[Item]:
+ return [
+ Item(name="Portal Gun", price=42.0),
+ Item(name="Plumbus", price=32.0),
+ ]
diff --git a/docs_src/response_model/tutorial001_01_py310.py b/docs_src/response_model/tutorial001_01_py310.py
new file mode 100644
index 000000000..7951c1076
--- /dev/null
+++ b/docs_src/response_model/tutorial001_01_py310.py
@@ -0,0 +1,25 @@
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: str | None = None
+ price: float
+ tax: float | None = None
+ tags: list[str] = []
+
+
+@app.post("/items/")
+async def create_item(item: Item) -> Item:
+ return item
+
+
+@app.get("/items/")
+async def read_items() -> list[Item]:
+ return [
+ Item(name="Portal Gun", price=42.0),
+ Item(name="Plumbus", price=32.0),
+ ]
diff --git a/docs_src/response_model/tutorial001_01_py39.py b/docs_src/response_model/tutorial001_01_py39.py
new file mode 100644
index 000000000..16c78aa3f
--- /dev/null
+++ b/docs_src/response_model/tutorial001_01_py39.py
@@ -0,0 +1,27 @@
+from typing import Union
+
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+ tags: list[str] = []
+
+
+@app.post("/items/")
+async def create_item(item: Item) -> Item:
+ return item
+
+
+@app.get("/items/")
+async def read_items() -> list[Item]:
+ return [
+ Item(name="Portal Gun", price=42.0),
+ Item(name="Plumbus", price=32.0),
+ ]
diff --git a/docs_src/response_model/tutorial001_py310.py b/docs_src/response_model/tutorial001_py310.py
index 59efecde4..f8a2aa9fc 100644
--- a/docs_src/response_model/tutorial001_py310.py
+++ b/docs_src/response_model/tutorial001_py310.py
@@ -1,3 +1,5 @@
+from typing import Any
+
from fastapi import FastAPI
from pydantic import BaseModel
@@ -13,5 +15,13 @@ class Item(BaseModel):
@app.post("/items/", response_model=Item)
-async def create_item(item: Item):
+async def create_item(item: Item) -> Any:
return item
+
+
+@app.get("/items/", response_model=list[Item])
+async def read_items() -> Any:
+ return [
+ {"name": "Portal Gun", "price": 42.0},
+ {"name": "Plumbus", "price": 32.0},
+ ]
diff --git a/docs_src/response_model/tutorial001_py39.py b/docs_src/response_model/tutorial001_py39.py
index cdcca39d2..261e252d0 100644
--- a/docs_src/response_model/tutorial001_py39.py
+++ b/docs_src/response_model/tutorial001_py39.py
@@ -1,4 +1,4 @@
-from typing import Union
+from typing import Any, Union
from fastapi import FastAPI
from pydantic import BaseModel
@@ -15,5 +15,13 @@ class Item(BaseModel):
@app.post("/items/", response_model=Item)
-async def create_item(item: Item):
+async def create_item(item: Item) -> Any:
return item
+
+
+@app.get("/items/", response_model=list[Item])
+async def read_items() -> Any:
+ return [
+ {"name": "Portal Gun", "price": 42.0},
+ {"name": "Plumbus", "price": 32.0},
+ ]
diff --git a/docs_src/response_model/tutorial002.py b/docs_src/response_model/tutorial002.py
index c68e8b138..a58668f9e 100644
--- a/docs_src/response_model/tutorial002.py
+++ b/docs_src/response_model/tutorial002.py
@@ -14,6 +14,6 @@ class UserIn(BaseModel):
# Don't do this in production!
-@app.post("/user/", response_model=UserIn)
-async def create_user(user: UserIn):
+@app.post("/user/")
+async def create_user(user: UserIn) -> UserIn:
return user
diff --git a/docs_src/response_model/tutorial002_py310.py b/docs_src/response_model/tutorial002_py310.py
index 29ab9c9d2..0a91a5967 100644
--- a/docs_src/response_model/tutorial002_py310.py
+++ b/docs_src/response_model/tutorial002_py310.py
@@ -12,6 +12,6 @@ class UserIn(BaseModel):
# Don't do this in production!
-@app.post("/user/", response_model=UserIn)
-async def create_user(user: UserIn):
+@app.post("/user/")
+async def create_user(user: UserIn) -> UserIn:
return user
diff --git a/docs_src/response_model/tutorial003.py b/docs_src/response_model/tutorial003.py
index 37e493dcb..c42dbc707 100644
--- a/docs_src/response_model/tutorial003.py
+++ b/docs_src/response_model/tutorial003.py
@@ -1,4 +1,4 @@
-from typing import Union
+from typing import Any, Union
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
@@ -20,5 +20,5 @@ class UserOut(BaseModel):
@app.post("/user/", response_model=UserOut)
-async def create_user(user: UserIn):
+async def create_user(user: UserIn) -> Any:
return user
diff --git a/docs_src/response_model/tutorial003_01.py b/docs_src/response_model/tutorial003_01.py
new file mode 100644
index 000000000..52694b551
--- /dev/null
+++ b/docs_src/response_model/tutorial003_01.py
@@ -0,0 +1,21 @@
+from typing import Union
+
+from fastapi import FastAPI
+from pydantic import BaseModel, EmailStr
+
+app = FastAPI()
+
+
+class BaseUser(BaseModel):
+ username: str
+ email: EmailStr
+ full_name: Union[str, None] = None
+
+
+class UserIn(BaseUser):
+ password: str
+
+
+@app.post("/user/")
+async def create_user(user: UserIn) -> BaseUser:
+ return user
diff --git a/docs_src/response_model/tutorial003_01_py310.py b/docs_src/response_model/tutorial003_01_py310.py
new file mode 100644
index 000000000..6ffddfd0a
--- /dev/null
+++ b/docs_src/response_model/tutorial003_01_py310.py
@@ -0,0 +1,19 @@
+from fastapi import FastAPI
+from pydantic import BaseModel, EmailStr
+
+app = FastAPI()
+
+
+class BaseUser(BaseModel):
+ username: str
+ email: EmailStr
+ full_name: str | None = None
+
+
+class UserIn(BaseUser):
+ password: str
+
+
+@app.post("/user/")
+async def create_user(user: UserIn) -> BaseUser:
+ return user
diff --git a/docs_src/response_model/tutorial003_02.py b/docs_src/response_model/tutorial003_02.py
new file mode 100644
index 000000000..df6a09646
--- /dev/null
+++ b/docs_src/response_model/tutorial003_02.py
@@ -0,0 +1,11 @@
+from fastapi import FastAPI, Response
+from fastapi.responses import JSONResponse, RedirectResponse
+
+app = FastAPI()
+
+
+@app.get("/portal")
+async def get_portal(teleport: bool = False) -> Response:
+ if teleport:
+ return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
+ return JSONResponse(content={"message": "Here's your interdimensional portal."})
diff --git a/docs_src/response_model/tutorial003_03.py b/docs_src/response_model/tutorial003_03.py
new file mode 100644
index 000000000..0d4bd8de5
--- /dev/null
+++ b/docs_src/response_model/tutorial003_03.py
@@ -0,0 +1,9 @@
+from fastapi import FastAPI
+from fastapi.responses import RedirectResponse
+
+app = FastAPI()
+
+
+@app.get("/teleport")
+async def get_teleport() -> RedirectResponse:
+ return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
diff --git a/docs_src/response_model/tutorial003_04.py b/docs_src/response_model/tutorial003_04.py
new file mode 100644
index 000000000..b13a92692
--- /dev/null
+++ b/docs_src/response_model/tutorial003_04.py
@@ -0,0 +1,13 @@
+from typing import Union
+
+from fastapi import FastAPI, Response
+from fastapi.responses import RedirectResponse
+
+app = FastAPI()
+
+
+@app.get("/portal")
+async def get_portal(teleport: bool = False) -> Union[Response, dict]:
+ if teleport:
+ return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
+ return {"message": "Here's your interdimensional portal."}
diff --git a/docs_src/response_model/tutorial003_04_py310.py b/docs_src/response_model/tutorial003_04_py310.py
new file mode 100644
index 000000000..cee49b83e
--- /dev/null
+++ b/docs_src/response_model/tutorial003_04_py310.py
@@ -0,0 +1,11 @@
+from fastapi import FastAPI, Response
+from fastapi.responses import RedirectResponse
+
+app = FastAPI()
+
+
+@app.get("/portal")
+async def get_portal(teleport: bool = False) -> Response | dict:
+ if teleport:
+ return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
+ return {"message": "Here's your interdimensional portal."}
diff --git a/docs_src/response_model/tutorial003_05.py b/docs_src/response_model/tutorial003_05.py
new file mode 100644
index 000000000..0962061a6
--- /dev/null
+++ b/docs_src/response_model/tutorial003_05.py
@@ -0,0 +1,13 @@
+from typing import Union
+
+from fastapi import FastAPI, Response
+from fastapi.responses import RedirectResponse
+
+app = FastAPI()
+
+
+@app.get("/portal", response_model=None)
+async def get_portal(teleport: bool = False) -> Union[Response, dict]:
+ if teleport:
+ return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
+ return {"message": "Here's your interdimensional portal."}
diff --git a/docs_src/response_model/tutorial003_05_py310.py b/docs_src/response_model/tutorial003_05_py310.py
new file mode 100644
index 000000000..f1c0f8e12
--- /dev/null
+++ b/docs_src/response_model/tutorial003_05_py310.py
@@ -0,0 +1,11 @@
+from fastapi import FastAPI, Response
+from fastapi.responses import RedirectResponse
+
+app = FastAPI()
+
+
+@app.get("/portal", response_model=None)
+async def get_portal(teleport: bool = False) -> Response | dict:
+ if teleport:
+ return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
+ return {"message": "Here's your interdimensional portal."}
diff --git a/docs_src/response_model/tutorial003_py310.py b/docs_src/response_model/tutorial003_py310.py
index fc9693e3c..3703bf888 100644
--- a/docs_src/response_model/tutorial003_py310.py
+++ b/docs_src/response_model/tutorial003_py310.py
@@ -1,3 +1,5 @@
+from typing import Any
+
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
@@ -18,5 +20,5 @@ class UserOut(BaseModel):
@app.post("/user/", response_model=UserOut)
-async def create_user(user: UserIn):
+async def create_user(user: UserIn) -> Any:
return user
diff --git a/docs_src/schema_extra_example/tutorial003_an.py b/docs_src/schema_extra_example/tutorial003_an.py
new file mode 100644
index 000000000..1dec555a9
--- /dev/null
+++ b/docs_src/schema_extra_example/tutorial003_an.py
@@ -0,0 +1,33 @@
+from typing import Union
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ item_id: int,
+ item: Annotated[
+ Item,
+ Body(
+ example={
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ },
+ ),
+ ],
+):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/schema_extra_example/tutorial003_an_py310.py b/docs_src/schema_extra_example/tutorial003_an_py310.py
new file mode 100644
index 000000000..9edaddfb8
--- /dev/null
+++ b/docs_src/schema_extra_example/tutorial003_an_py310.py
@@ -0,0 +1,32 @@
+from typing import Annotated
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: str | None = None
+ price: float
+ tax: float | None = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ item_id: int,
+ item: Annotated[
+ Item,
+ Body(
+ example={
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ },
+ ),
+ ],
+):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/schema_extra_example/tutorial003_an_py39.py b/docs_src/schema_extra_example/tutorial003_an_py39.py
new file mode 100644
index 000000000..fe08847d9
--- /dev/null
+++ b/docs_src/schema_extra_example/tutorial003_an_py39.py
@@ -0,0 +1,32 @@
+from typing import Annotated, Union
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ item_id: int,
+ item: Annotated[
+ Item,
+ Body(
+ example={
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ },
+ ),
+ ],
+):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/schema_extra_example/tutorial004_an.py b/docs_src/schema_extra_example/tutorial004_an.py
new file mode 100644
index 000000000..82c9a92ac
--- /dev/null
+++ b/docs_src/schema_extra_example/tutorial004_an.py
@@ -0,0 +1,55 @@
+from typing import Union
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ *,
+ item_id: int,
+ item: Annotated[
+ Item,
+ Body(
+ examples={
+ "normal": {
+ "summary": "A normal example",
+ "description": "A **normal** item works correctly.",
+ "value": {
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ },
+ },
+ "converted": {
+ "summary": "An example with converted data",
+ "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
+ "value": {
+ "name": "Bar",
+ "price": "35.4",
+ },
+ },
+ "invalid": {
+ "summary": "Invalid data is rejected with an error",
+ "value": {
+ "name": "Baz",
+ "price": "thirty five point four",
+ },
+ },
+ },
+ ),
+ ],
+):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/schema_extra_example/tutorial004_an_py310.py b/docs_src/schema_extra_example/tutorial004_an_py310.py
new file mode 100644
index 000000000..01f1a486c
--- /dev/null
+++ b/docs_src/schema_extra_example/tutorial004_an_py310.py
@@ -0,0 +1,54 @@
+from typing import Annotated
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: str | None = None
+ price: float
+ tax: float | None = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ *,
+ item_id: int,
+ item: Annotated[
+ Item,
+ Body(
+ examples={
+ "normal": {
+ "summary": "A normal example",
+ "description": "A **normal** item works correctly.",
+ "value": {
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ },
+ },
+ "converted": {
+ "summary": "An example with converted data",
+ "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
+ "value": {
+ "name": "Bar",
+ "price": "35.4",
+ },
+ },
+ "invalid": {
+ "summary": "Invalid data is rejected with an error",
+ "value": {
+ "name": "Baz",
+ "price": "thirty five point four",
+ },
+ },
+ },
+ ),
+ ],
+):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/schema_extra_example/tutorial004_an_py39.py b/docs_src/schema_extra_example/tutorial004_an_py39.py
new file mode 100644
index 000000000..d50e8aa5f
--- /dev/null
+++ b/docs_src/schema_extra_example/tutorial004_an_py39.py
@@ -0,0 +1,54 @@
+from typing import Annotated, Union
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ *,
+ item_id: int,
+ item: Annotated[
+ Item,
+ Body(
+ examples={
+ "normal": {
+ "summary": "A normal example",
+ "description": "A **normal** item works correctly.",
+ "value": {
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ },
+ },
+ "converted": {
+ "summary": "An example with converted data",
+ "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
+ "value": {
+ "name": "Bar",
+ "price": "35.4",
+ },
+ },
+ "invalid": {
+ "summary": "Invalid data is rejected with an error",
+ "value": {
+ "name": "Baz",
+ "price": "thirty five point four",
+ },
+ },
+ },
+ ),
+ ],
+):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/security/tutorial001_an.py b/docs_src/security/tutorial001_an.py
new file mode 100644
index 000000000..dac915b7c
--- /dev/null
+++ b/docs_src/security/tutorial001_an.py
@@ -0,0 +1,12 @@
+from fastapi import Depends, FastAPI
+from fastapi.security import OAuth2PasswordBearer
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
+
+
+@app.get("/items/")
+async def read_items(token: Annotated[str, Depends(oauth2_scheme)]):
+ return {"token": token}
diff --git a/docs_src/security/tutorial001_an_py39.py b/docs_src/security/tutorial001_an_py39.py
new file mode 100644
index 000000000..de110402e
--- /dev/null
+++ b/docs_src/security/tutorial001_an_py39.py
@@ -0,0 +1,13 @@
+from typing import Annotated
+
+from fastapi import Depends, FastAPI
+from fastapi.security import OAuth2PasswordBearer
+
+app = FastAPI()
+
+oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
+
+
+@app.get("/items/")
+async def read_items(token: Annotated[str, Depends(oauth2_scheme)]):
+ return {"token": token}
diff --git a/docs_src/security/tutorial002_an.py b/docs_src/security/tutorial002_an.py
new file mode 100644
index 000000000..291b3bf53
--- /dev/null
+++ b/docs_src/security/tutorial002_an.py
@@ -0,0 +1,33 @@
+from typing import Union
+
+from fastapi import Depends, FastAPI
+from fastapi.security import OAuth2PasswordBearer
+from pydantic import BaseModel
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
+
+
+class User(BaseModel):
+ username: str
+ email: Union[str, None] = None
+ full_name: Union[str, None] = None
+ disabled: Union[bool, None] = None
+
+
+def fake_decode_token(token):
+ return User(
+ username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
+ )
+
+
+async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
+ user = fake_decode_token(token)
+ return user
+
+
+@app.get("/users/me")
+async def read_users_me(current_user: Annotated[User, Depends(get_current_user)]):
+ return current_user
diff --git a/docs_src/security/tutorial002_an_py310.py b/docs_src/security/tutorial002_an_py310.py
new file mode 100644
index 000000000..c7b761e45
--- /dev/null
+++ b/docs_src/security/tutorial002_an_py310.py
@@ -0,0 +1,32 @@
+from typing import Annotated
+
+from fastapi import Depends, FastAPI
+from fastapi.security import OAuth2PasswordBearer
+from pydantic import BaseModel
+
+app = FastAPI()
+
+oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
+
+
+class User(BaseModel):
+ username: str
+ email: str | None = None
+ full_name: str | None = None
+ disabled: bool | None = None
+
+
+def fake_decode_token(token):
+ return User(
+ username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
+ )
+
+
+async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
+ user = fake_decode_token(token)
+ return user
+
+
+@app.get("/users/me")
+async def read_users_me(current_user: Annotated[User, Depends(get_current_user)]):
+ return current_user
diff --git a/docs_src/security/tutorial002_an_py39.py b/docs_src/security/tutorial002_an_py39.py
new file mode 100644
index 000000000..7ff1c470b
--- /dev/null
+++ b/docs_src/security/tutorial002_an_py39.py
@@ -0,0 +1,32 @@
+from typing import Annotated, Union
+
+from fastapi import Depends, FastAPI
+from fastapi.security import OAuth2PasswordBearer
+from pydantic import BaseModel
+
+app = FastAPI()
+
+oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
+
+
+class User(BaseModel):
+ username: str
+ email: Union[str, None] = None
+ full_name: Union[str, None] = None
+ disabled: Union[bool, None] = None
+
+
+def fake_decode_token(token):
+ return User(
+ username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
+ )
+
+
+async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
+ user = fake_decode_token(token)
+ return user
+
+
+@app.get("/users/me")
+async def read_users_me(current_user: Annotated[User, Depends(get_current_user)]):
+ return current_user
diff --git a/docs_src/security/tutorial003_an.py b/docs_src/security/tutorial003_an.py
new file mode 100644
index 000000000..261cb4857
--- /dev/null
+++ b/docs_src/security/tutorial003_an.py
@@ -0,0 +1,95 @@
+from typing import Union
+
+from fastapi import Depends, FastAPI, HTTPException, status
+from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
+from pydantic import BaseModel
+from typing_extensions import Annotated
+
+fake_users_db = {
+ "johndoe": {
+ "username": "johndoe",
+ "full_name": "John Doe",
+ "email": "johndoe@example.com",
+ "hashed_password": "fakehashedsecret",
+ "disabled": False,
+ },
+ "alice": {
+ "username": "alice",
+ "full_name": "Alice Wonderson",
+ "email": "alice@example.com",
+ "hashed_password": "fakehashedsecret2",
+ "disabled": True,
+ },
+}
+
+app = FastAPI()
+
+
+def fake_hash_password(password: str):
+ return "fakehashed" + password
+
+
+oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
+
+
+class User(BaseModel):
+ username: str
+ email: Union[str, None] = None
+ full_name: Union[str, None] = None
+ disabled: Union[bool, None] = None
+
+
+class UserInDB(User):
+ hashed_password: str
+
+
+def get_user(db, username: str):
+ if username in db:
+ user_dict = db[username]
+ return UserInDB(**user_dict)
+
+
+def fake_decode_token(token):
+ # This doesn't provide any security at all
+ # Check the next version
+ user = get_user(fake_users_db, token)
+ return user
+
+
+async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
+ user = fake_decode_token(token)
+ if not user:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Invalid authentication credentials",
+ headers={"WWW-Authenticate": "Bearer"},
+ )
+ return user
+
+
+async def get_current_active_user(
+ current_user: Annotated[User, Depends(get_current_user)]
+):
+ if current_user.disabled:
+ raise HTTPException(status_code=400, detail="Inactive user")
+ return current_user
+
+
+@app.post("/token")
+async def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):
+ user_dict = fake_users_db.get(form_data.username)
+ if not user_dict:
+ raise HTTPException(status_code=400, detail="Incorrect username or password")
+ user = UserInDB(**user_dict)
+ hashed_password = fake_hash_password(form_data.password)
+ if not hashed_password == user.hashed_password:
+ raise HTTPException(status_code=400, detail="Incorrect username or password")
+
+ return {"access_token": user.username, "token_type": "bearer"}
+
+
+@app.get("/users/me")
+async def read_users_me(
+ current_user: Annotated[User, Depends(get_current_active_user)]
+):
+ return current_user
diff --git a/docs_src/security/tutorial003_an_py310.py b/docs_src/security/tutorial003_an_py310.py
new file mode 100644
index 000000000..a03f4f8bf
--- /dev/null
+++ b/docs_src/security/tutorial003_an_py310.py
@@ -0,0 +1,94 @@
+from typing import Annotated
+
+from fastapi import Depends, FastAPI, HTTPException, status
+from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
+from pydantic import BaseModel
+
+fake_users_db = {
+ "johndoe": {
+ "username": "johndoe",
+ "full_name": "John Doe",
+ "email": "johndoe@example.com",
+ "hashed_password": "fakehashedsecret",
+ "disabled": False,
+ },
+ "alice": {
+ "username": "alice",
+ "full_name": "Alice Wonderson",
+ "email": "alice@example.com",
+ "hashed_password": "fakehashedsecret2",
+ "disabled": True,
+ },
+}
+
+app = FastAPI()
+
+
+def fake_hash_password(password: str):
+ return "fakehashed" + password
+
+
+oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
+
+
+class User(BaseModel):
+ username: str
+ email: str | None = None
+ full_name: str | None = None
+ disabled: bool | None = None
+
+
+class UserInDB(User):
+ hashed_password: str
+
+
+def get_user(db, username: str):
+ if username in db:
+ user_dict = db[username]
+ return UserInDB(**user_dict)
+
+
+def fake_decode_token(token):
+ # This doesn't provide any security at all
+ # Check the next version
+ user = get_user(fake_users_db, token)
+ return user
+
+
+async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
+ user = fake_decode_token(token)
+ if not user:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Invalid authentication credentials",
+ headers={"WWW-Authenticate": "Bearer"},
+ )
+ return user
+
+
+async def get_current_active_user(
+ current_user: Annotated[User, Depends(get_current_user)]
+):
+ if current_user.disabled:
+ raise HTTPException(status_code=400, detail="Inactive user")
+ return current_user
+
+
+@app.post("/token")
+async def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):
+ user_dict = fake_users_db.get(form_data.username)
+ if not user_dict:
+ raise HTTPException(status_code=400, detail="Incorrect username or password")
+ user = UserInDB(**user_dict)
+ hashed_password = fake_hash_password(form_data.password)
+ if not hashed_password == user.hashed_password:
+ raise HTTPException(status_code=400, detail="Incorrect username or password")
+
+ return {"access_token": user.username, "token_type": "bearer"}
+
+
+@app.get("/users/me")
+async def read_users_me(
+ current_user: Annotated[User, Depends(get_current_active_user)]
+):
+ return current_user
diff --git a/docs_src/security/tutorial003_an_py39.py b/docs_src/security/tutorial003_an_py39.py
new file mode 100644
index 000000000..308dbe798
--- /dev/null
+++ b/docs_src/security/tutorial003_an_py39.py
@@ -0,0 +1,94 @@
+from typing import Annotated, Union
+
+from fastapi import Depends, FastAPI, HTTPException, status
+from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
+from pydantic import BaseModel
+
+fake_users_db = {
+ "johndoe": {
+ "username": "johndoe",
+ "full_name": "John Doe",
+ "email": "johndoe@example.com",
+ "hashed_password": "fakehashedsecret",
+ "disabled": False,
+ },
+ "alice": {
+ "username": "alice",
+ "full_name": "Alice Wonderson",
+ "email": "alice@example.com",
+ "hashed_password": "fakehashedsecret2",
+ "disabled": True,
+ },
+}
+
+app = FastAPI()
+
+
+def fake_hash_password(password: str):
+ return "fakehashed" + password
+
+
+oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
+
+
+class User(BaseModel):
+ username: str
+ email: Union[str, None] = None
+ full_name: Union[str, None] = None
+ disabled: Union[bool, None] = None
+
+
+class UserInDB(User):
+ hashed_password: str
+
+
+def get_user(db, username: str):
+ if username in db:
+ user_dict = db[username]
+ return UserInDB(**user_dict)
+
+
+def fake_decode_token(token):
+ # This doesn't provide any security at all
+ # Check the next version
+ user = get_user(fake_users_db, token)
+ return user
+
+
+async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
+ user = fake_decode_token(token)
+ if not user:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Invalid authentication credentials",
+ headers={"WWW-Authenticate": "Bearer"},
+ )
+ return user
+
+
+async def get_current_active_user(
+ current_user: Annotated[User, Depends(get_current_user)]
+):
+ if current_user.disabled:
+ raise HTTPException(status_code=400, detail="Inactive user")
+ return current_user
+
+
+@app.post("/token")
+async def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):
+ user_dict = fake_users_db.get(form_data.username)
+ if not user_dict:
+ raise HTTPException(status_code=400, detail="Incorrect username or password")
+ user = UserInDB(**user_dict)
+ hashed_password = fake_hash_password(form_data.password)
+ if not hashed_password == user.hashed_password:
+ raise HTTPException(status_code=400, detail="Incorrect username or password")
+
+ return {"access_token": user.username, "token_type": "bearer"}
+
+
+@app.get("/users/me")
+async def read_users_me(
+ current_user: Annotated[User, Depends(get_current_active_user)]
+):
+ return current_user
diff --git a/docs_src/security/tutorial004_an.py b/docs_src/security/tutorial004_an.py
new file mode 100644
index 000000000..ca350343d
--- /dev/null
+++ b/docs_src/security/tutorial004_an.py
@@ -0,0 +1,147 @@
+from datetime import datetime, timedelta
+from typing import Union
+
+from fastapi import Depends, FastAPI, HTTPException, status
+from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
+from jose import JWTError, jwt
+from passlib.context import CryptContext
+from pydantic import BaseModel
+from typing_extensions import Annotated
+
+# to get a string like this run:
+# openssl rand -hex 32
+SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
+ALGORITHM = "HS256"
+ACCESS_TOKEN_EXPIRE_MINUTES = 30
+
+
+fake_users_db = {
+ "johndoe": {
+ "username": "johndoe",
+ "full_name": "John Doe",
+ "email": "johndoe@example.com",
+ "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW",
+ "disabled": False,
+ }
+}
+
+
+class Token(BaseModel):
+ access_token: str
+ token_type: str
+
+
+class TokenData(BaseModel):
+ username: Union[str, None] = None
+
+
+class User(BaseModel):
+ username: str
+ email: Union[str, None] = None
+ full_name: Union[str, None] = None
+ disabled: Union[bool, None] = None
+
+
+class UserInDB(User):
+ hashed_password: str
+
+
+pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
+
+oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
+
+app = FastAPI()
+
+
+def verify_password(plain_password, hashed_password):
+ return pwd_context.verify(plain_password, hashed_password)
+
+
+def get_password_hash(password):
+ return pwd_context.hash(password)
+
+
+def get_user(db, username: str):
+ if username in db:
+ user_dict = db[username]
+ return UserInDB(**user_dict)
+
+
+def authenticate_user(fake_db, username: str, password: str):
+ user = get_user(fake_db, username)
+ if not user:
+ return False
+ if not verify_password(password, user.hashed_password):
+ return False
+ return user
+
+
+def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
+ to_encode = data.copy()
+ if expires_delta:
+ expire = datetime.utcnow() + expires_delta
+ else:
+ expire = datetime.utcnow() + timedelta(minutes=15)
+ to_encode.update({"exp": expire})
+ encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
+ return encoded_jwt
+
+
+async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
+ credentials_exception = HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Could not validate credentials",
+ headers={"WWW-Authenticate": "Bearer"},
+ )
+ try:
+ payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
+ username: str = payload.get("sub")
+ if username is None:
+ raise credentials_exception
+ token_data = TokenData(username=username)
+ except JWTError:
+ raise credentials_exception
+ user = get_user(fake_users_db, username=token_data.username)
+ if user is None:
+ raise credentials_exception
+ return user
+
+
+async def get_current_active_user(
+ current_user: Annotated[User, Depends(get_current_user)]
+):
+ if current_user.disabled:
+ raise HTTPException(status_code=400, detail="Inactive user")
+ return current_user
+
+
+@app.post("/token", response_model=Token)
+async def login_for_access_token(
+ form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
+):
+ user = authenticate_user(fake_users_db, form_data.username, form_data.password)
+ if not user:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Incorrect username or password",
+ headers={"WWW-Authenticate": "Bearer"},
+ )
+ access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
+ access_token = create_access_token(
+ data={"sub": user.username}, expires_delta=access_token_expires
+ )
+ return {"access_token": access_token, "token_type": "bearer"}
+
+
+@app.get("/users/me/", response_model=User)
+async def read_users_me(
+ current_user: Annotated[User, Depends(get_current_active_user)]
+):
+ return current_user
+
+
+@app.get("/users/me/items/")
+async def read_own_items(
+ current_user: Annotated[User, Depends(get_current_active_user)]
+):
+ return [{"item_id": "Foo", "owner": current_user.username}]
diff --git a/docs_src/security/tutorial004_an_py310.py b/docs_src/security/tutorial004_an_py310.py
new file mode 100644
index 000000000..8bf5f3b71
--- /dev/null
+++ b/docs_src/security/tutorial004_an_py310.py
@@ -0,0 +1,146 @@
+from datetime import datetime, timedelta
+from typing import Annotated
+
+from fastapi import Depends, FastAPI, HTTPException, status
+from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
+from jose import JWTError, jwt
+from passlib.context import CryptContext
+from pydantic import BaseModel
+
+# to get a string like this run:
+# openssl rand -hex 32
+SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
+ALGORITHM = "HS256"
+ACCESS_TOKEN_EXPIRE_MINUTES = 30
+
+
+fake_users_db = {
+ "johndoe": {
+ "username": "johndoe",
+ "full_name": "John Doe",
+ "email": "johndoe@example.com",
+ "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW",
+ "disabled": False,
+ }
+}
+
+
+class Token(BaseModel):
+ access_token: str
+ token_type: str
+
+
+class TokenData(BaseModel):
+ username: str | None = None
+
+
+class User(BaseModel):
+ username: str
+ email: str | None = None
+ full_name: str | None = None
+ disabled: bool | None = None
+
+
+class UserInDB(User):
+ hashed_password: str
+
+
+pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
+
+oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
+
+app = FastAPI()
+
+
+def verify_password(plain_password, hashed_password):
+ return pwd_context.verify(plain_password, hashed_password)
+
+
+def get_password_hash(password):
+ return pwd_context.hash(password)
+
+
+def get_user(db, username: str):
+ if username in db:
+ user_dict = db[username]
+ return UserInDB(**user_dict)
+
+
+def authenticate_user(fake_db, username: str, password: str):
+ user = get_user(fake_db, username)
+ if not user:
+ return False
+ if not verify_password(password, user.hashed_password):
+ return False
+ return user
+
+
+def create_access_token(data: dict, expires_delta: timedelta | None = None):
+ to_encode = data.copy()
+ if expires_delta:
+ expire = datetime.utcnow() + expires_delta
+ else:
+ expire = datetime.utcnow() + timedelta(minutes=15)
+ to_encode.update({"exp": expire})
+ encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
+ return encoded_jwt
+
+
+async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
+ credentials_exception = HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Could not validate credentials",
+ headers={"WWW-Authenticate": "Bearer"},
+ )
+ try:
+ payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
+ username: str = payload.get("sub")
+ if username is None:
+ raise credentials_exception
+ token_data = TokenData(username=username)
+ except JWTError:
+ raise credentials_exception
+ user = get_user(fake_users_db, username=token_data.username)
+ if user is None:
+ raise credentials_exception
+ return user
+
+
+async def get_current_active_user(
+ current_user: Annotated[User, Depends(get_current_user)]
+):
+ if current_user.disabled:
+ raise HTTPException(status_code=400, detail="Inactive user")
+ return current_user
+
+
+@app.post("/token", response_model=Token)
+async def login_for_access_token(
+ form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
+):
+ user = authenticate_user(fake_users_db, form_data.username, form_data.password)
+ if not user:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Incorrect username or password",
+ headers={"WWW-Authenticate": "Bearer"},
+ )
+ access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
+ access_token = create_access_token(
+ data={"sub": user.username}, expires_delta=access_token_expires
+ )
+ return {"access_token": access_token, "token_type": "bearer"}
+
+
+@app.get("/users/me/", response_model=User)
+async def read_users_me(
+ current_user: Annotated[User, Depends(get_current_active_user)]
+):
+ return current_user
+
+
+@app.get("/users/me/items/")
+async def read_own_items(
+ current_user: Annotated[User, Depends(get_current_active_user)]
+):
+ return [{"item_id": "Foo", "owner": current_user.username}]
diff --git a/docs_src/security/tutorial004_an_py39.py b/docs_src/security/tutorial004_an_py39.py
new file mode 100644
index 000000000..a634e23de
--- /dev/null
+++ b/docs_src/security/tutorial004_an_py39.py
@@ -0,0 +1,146 @@
+from datetime import datetime, timedelta
+from typing import Annotated, Union
+
+from fastapi import Depends, FastAPI, HTTPException, status
+from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
+from jose import JWTError, jwt
+from passlib.context import CryptContext
+from pydantic import BaseModel
+
+# to get a string like this run:
+# openssl rand -hex 32
+SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
+ALGORITHM = "HS256"
+ACCESS_TOKEN_EXPIRE_MINUTES = 30
+
+
+fake_users_db = {
+ "johndoe": {
+ "username": "johndoe",
+ "full_name": "John Doe",
+ "email": "johndoe@example.com",
+ "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW",
+ "disabled": False,
+ }
+}
+
+
+class Token(BaseModel):
+ access_token: str
+ token_type: str
+
+
+class TokenData(BaseModel):
+ username: Union[str, None] = None
+
+
+class User(BaseModel):
+ username: str
+ email: Union[str, None] = None
+ full_name: Union[str, None] = None
+ disabled: Union[bool, None] = None
+
+
+class UserInDB(User):
+ hashed_password: str
+
+
+pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
+
+oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
+
+app = FastAPI()
+
+
+def verify_password(plain_password, hashed_password):
+ return pwd_context.verify(plain_password, hashed_password)
+
+
+def get_password_hash(password):
+ return pwd_context.hash(password)
+
+
+def get_user(db, username: str):
+ if username in db:
+ user_dict = db[username]
+ return UserInDB(**user_dict)
+
+
+def authenticate_user(fake_db, username: str, password: str):
+ user = get_user(fake_db, username)
+ if not user:
+ return False
+ if not verify_password(password, user.hashed_password):
+ return False
+ return user
+
+
+def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
+ to_encode = data.copy()
+ if expires_delta:
+ expire = datetime.utcnow() + expires_delta
+ else:
+ expire = datetime.utcnow() + timedelta(minutes=15)
+ to_encode.update({"exp": expire})
+ encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
+ return encoded_jwt
+
+
+async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
+ credentials_exception = HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Could not validate credentials",
+ headers={"WWW-Authenticate": "Bearer"},
+ )
+ try:
+ payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
+ username: str = payload.get("sub")
+ if username is None:
+ raise credentials_exception
+ token_data = TokenData(username=username)
+ except JWTError:
+ raise credentials_exception
+ user = get_user(fake_users_db, username=token_data.username)
+ if user is None:
+ raise credentials_exception
+ return user
+
+
+async def get_current_active_user(
+ current_user: Annotated[User, Depends(get_current_user)]
+):
+ if current_user.disabled:
+ raise HTTPException(status_code=400, detail="Inactive user")
+ return current_user
+
+
+@app.post("/token", response_model=Token)
+async def login_for_access_token(
+ form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
+):
+ user = authenticate_user(fake_users_db, form_data.username, form_data.password)
+ if not user:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Incorrect username or password",
+ headers={"WWW-Authenticate": "Bearer"},
+ )
+ access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
+ access_token = create_access_token(
+ data={"sub": user.username}, expires_delta=access_token_expires
+ )
+ return {"access_token": access_token, "token_type": "bearer"}
+
+
+@app.get("/users/me/", response_model=User)
+async def read_users_me(
+ current_user: Annotated[User, Depends(get_current_active_user)]
+):
+ return current_user
+
+
+@app.get("/users/me/items/")
+async def read_own_items(
+ current_user: Annotated[User, Depends(get_current_active_user)]
+):
+ return [{"item_id": "Foo", "owner": current_user.username}]
diff --git a/docs_src/security/tutorial005_an.py b/docs_src/security/tutorial005_an.py
new file mode 100644
index 000000000..ec4fa1a07
--- /dev/null
+++ b/docs_src/security/tutorial005_an.py
@@ -0,0 +1,178 @@
+from datetime import datetime, timedelta
+from typing import List, Union
+
+from fastapi import Depends, FastAPI, HTTPException, Security, status
+from fastapi.security import (
+ OAuth2PasswordBearer,
+ OAuth2PasswordRequestForm,
+ SecurityScopes,
+)
+from jose import JWTError, jwt
+from passlib.context import CryptContext
+from pydantic import BaseModel, ValidationError
+from typing_extensions import Annotated
+
+# to get a string like this run:
+# openssl rand -hex 32
+SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
+ALGORITHM = "HS256"
+ACCESS_TOKEN_EXPIRE_MINUTES = 30
+
+
+fake_users_db = {
+ "johndoe": {
+ "username": "johndoe",
+ "full_name": "John Doe",
+ "email": "johndoe@example.com",
+ "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW",
+ "disabled": False,
+ },
+ "alice": {
+ "username": "alice",
+ "full_name": "Alice Chains",
+ "email": "alicechains@example.com",
+ "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm",
+ "disabled": True,
+ },
+}
+
+
+class Token(BaseModel):
+ access_token: str
+ token_type: str
+
+
+class TokenData(BaseModel):
+ username: Union[str, None] = None
+ scopes: List[str] = []
+
+
+class User(BaseModel):
+ username: str
+ email: Union[str, None] = None
+ full_name: Union[str, None] = None
+ disabled: Union[bool, None] = None
+
+
+class UserInDB(User):
+ hashed_password: str
+
+
+pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
+
+oauth2_scheme = OAuth2PasswordBearer(
+ tokenUrl="token",
+ scopes={"me": "Read information about the current user.", "items": "Read items."},
+)
+
+app = FastAPI()
+
+
+def verify_password(plain_password, hashed_password):
+ return pwd_context.verify(plain_password, hashed_password)
+
+
+def get_password_hash(password):
+ return pwd_context.hash(password)
+
+
+def get_user(db, username: str):
+ if username in db:
+ user_dict = db[username]
+ return UserInDB(**user_dict)
+
+
+def authenticate_user(fake_db, username: str, password: str):
+ user = get_user(fake_db, username)
+ if not user:
+ return False
+ if not verify_password(password, user.hashed_password):
+ return False
+ return user
+
+
+def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
+ to_encode = data.copy()
+ if expires_delta:
+ expire = datetime.utcnow() + expires_delta
+ else:
+ expire = datetime.utcnow() + timedelta(minutes=15)
+ to_encode.update({"exp": expire})
+ encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
+ return encoded_jwt
+
+
+async def get_current_user(
+ security_scopes: SecurityScopes, token: Annotated[str, Depends(oauth2_scheme)]
+):
+ if security_scopes.scopes:
+ authenticate_value = f'Bearer scope="{security_scopes.scope_str}"'
+ else:
+ authenticate_value = "Bearer"
+ credentials_exception = HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Could not validate credentials",
+ headers={"WWW-Authenticate": authenticate_value},
+ )
+ try:
+ payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
+ username: str = payload.get("sub")
+ if username is None:
+ raise credentials_exception
+ token_scopes = payload.get("scopes", [])
+ token_data = TokenData(scopes=token_scopes, username=username)
+ except (JWTError, ValidationError):
+ raise credentials_exception
+ user = get_user(fake_users_db, username=token_data.username)
+ if user is None:
+ raise credentials_exception
+ for scope in security_scopes.scopes:
+ if scope not in token_data.scopes:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Not enough permissions",
+ headers={"WWW-Authenticate": authenticate_value},
+ )
+ return user
+
+
+async def get_current_active_user(
+ current_user: Annotated[User, Security(get_current_user, scopes=["me"])]
+):
+ if current_user.disabled:
+ raise HTTPException(status_code=400, detail="Inactive user")
+ return current_user
+
+
+@app.post("/token", response_model=Token)
+async def login_for_access_token(
+ form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
+):
+ user = authenticate_user(fake_users_db, form_data.username, form_data.password)
+ if not user:
+ raise HTTPException(status_code=400, detail="Incorrect username or password")
+ access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
+ access_token = create_access_token(
+ data={"sub": user.username, "scopes": form_data.scopes},
+ expires_delta=access_token_expires,
+ )
+ return {"access_token": access_token, "token_type": "bearer"}
+
+
+@app.get("/users/me/", response_model=User)
+async def read_users_me(
+ current_user: Annotated[User, Depends(get_current_active_user)]
+):
+ return current_user
+
+
+@app.get("/users/me/items/")
+async def read_own_items(
+ current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])]
+):
+ return [{"item_id": "Foo", "owner": current_user.username}]
+
+
+@app.get("/status/")
+async def read_system_status(current_user: Annotated[User, Depends(get_current_user)]):
+ return {"status": "ok"}
diff --git a/docs_src/security/tutorial005_an_py310.py b/docs_src/security/tutorial005_an_py310.py
new file mode 100644
index 000000000..45f3fc0bd
--- /dev/null
+++ b/docs_src/security/tutorial005_an_py310.py
@@ -0,0 +1,177 @@
+from datetime import datetime, timedelta
+from typing import Annotated
+
+from fastapi import Depends, FastAPI, HTTPException, Security, status
+from fastapi.security import (
+ OAuth2PasswordBearer,
+ OAuth2PasswordRequestForm,
+ SecurityScopes,
+)
+from jose import JWTError, jwt
+from passlib.context import CryptContext
+from pydantic import BaseModel, ValidationError
+
+# to get a string like this run:
+# openssl rand -hex 32
+SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
+ALGORITHM = "HS256"
+ACCESS_TOKEN_EXPIRE_MINUTES = 30
+
+
+fake_users_db = {
+ "johndoe": {
+ "username": "johndoe",
+ "full_name": "John Doe",
+ "email": "johndoe@example.com",
+ "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW",
+ "disabled": False,
+ },
+ "alice": {
+ "username": "alice",
+ "full_name": "Alice Chains",
+ "email": "alicechains@example.com",
+ "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm",
+ "disabled": True,
+ },
+}
+
+
+class Token(BaseModel):
+ access_token: str
+ token_type: str
+
+
+class TokenData(BaseModel):
+ username: str | None = None
+ scopes: list[str] = []
+
+
+class User(BaseModel):
+ username: str
+ email: str | None = None
+ full_name: str | None = None
+ disabled: bool | None = None
+
+
+class UserInDB(User):
+ hashed_password: str
+
+
+pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
+
+oauth2_scheme = OAuth2PasswordBearer(
+ tokenUrl="token",
+ scopes={"me": "Read information about the current user.", "items": "Read items."},
+)
+
+app = FastAPI()
+
+
+def verify_password(plain_password, hashed_password):
+ return pwd_context.verify(plain_password, hashed_password)
+
+
+def get_password_hash(password):
+ return pwd_context.hash(password)
+
+
+def get_user(db, username: str):
+ if username in db:
+ user_dict = db[username]
+ return UserInDB(**user_dict)
+
+
+def authenticate_user(fake_db, username: str, password: str):
+ user = get_user(fake_db, username)
+ if not user:
+ return False
+ if not verify_password(password, user.hashed_password):
+ return False
+ return user
+
+
+def create_access_token(data: dict, expires_delta: timedelta | None = None):
+ to_encode = data.copy()
+ if expires_delta:
+ expire = datetime.utcnow() + expires_delta
+ else:
+ expire = datetime.utcnow() + timedelta(minutes=15)
+ to_encode.update({"exp": expire})
+ encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
+ return encoded_jwt
+
+
+async def get_current_user(
+ security_scopes: SecurityScopes, token: Annotated[str, Depends(oauth2_scheme)]
+):
+ if security_scopes.scopes:
+ authenticate_value = f'Bearer scope="{security_scopes.scope_str}"'
+ else:
+ authenticate_value = "Bearer"
+ credentials_exception = HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Could not validate credentials",
+ headers={"WWW-Authenticate": authenticate_value},
+ )
+ try:
+ payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
+ username: str = payload.get("sub")
+ if username is None:
+ raise credentials_exception
+ token_scopes = payload.get("scopes", [])
+ token_data = TokenData(scopes=token_scopes, username=username)
+ except (JWTError, ValidationError):
+ raise credentials_exception
+ user = get_user(fake_users_db, username=token_data.username)
+ if user is None:
+ raise credentials_exception
+ for scope in security_scopes.scopes:
+ if scope not in token_data.scopes:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Not enough permissions",
+ headers={"WWW-Authenticate": authenticate_value},
+ )
+ return user
+
+
+async def get_current_active_user(
+ current_user: Annotated[User, Security(get_current_user, scopes=["me"])]
+):
+ if current_user.disabled:
+ raise HTTPException(status_code=400, detail="Inactive user")
+ return current_user
+
+
+@app.post("/token", response_model=Token)
+async def login_for_access_token(
+ form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
+):
+ user = authenticate_user(fake_users_db, form_data.username, form_data.password)
+ if not user:
+ raise HTTPException(status_code=400, detail="Incorrect username or password")
+ access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
+ access_token = create_access_token(
+ data={"sub": user.username, "scopes": form_data.scopes},
+ expires_delta=access_token_expires,
+ )
+ return {"access_token": access_token, "token_type": "bearer"}
+
+
+@app.get("/users/me/", response_model=User)
+async def read_users_me(
+ current_user: Annotated[User, Depends(get_current_active_user)]
+):
+ return current_user
+
+
+@app.get("/users/me/items/")
+async def read_own_items(
+ current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])]
+):
+ return [{"item_id": "Foo", "owner": current_user.username}]
+
+
+@app.get("/status/")
+async def read_system_status(current_user: Annotated[User, Depends(get_current_user)]):
+ return {"status": "ok"}
diff --git a/docs_src/security/tutorial005_an_py39.py b/docs_src/security/tutorial005_an_py39.py
new file mode 100644
index 000000000..ecb5ed516
--- /dev/null
+++ b/docs_src/security/tutorial005_an_py39.py
@@ -0,0 +1,177 @@
+from datetime import datetime, timedelta
+from typing import Annotated, List, Union
+
+from fastapi import Depends, FastAPI, HTTPException, Security, status
+from fastapi.security import (
+ OAuth2PasswordBearer,
+ OAuth2PasswordRequestForm,
+ SecurityScopes,
+)
+from jose import JWTError, jwt
+from passlib.context import CryptContext
+from pydantic import BaseModel, ValidationError
+
+# to get a string like this run:
+# openssl rand -hex 32
+SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
+ALGORITHM = "HS256"
+ACCESS_TOKEN_EXPIRE_MINUTES = 30
+
+
+fake_users_db = {
+ "johndoe": {
+ "username": "johndoe",
+ "full_name": "John Doe",
+ "email": "johndoe@example.com",
+ "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW",
+ "disabled": False,
+ },
+ "alice": {
+ "username": "alice",
+ "full_name": "Alice Chains",
+ "email": "alicechains@example.com",
+ "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm",
+ "disabled": True,
+ },
+}
+
+
+class Token(BaseModel):
+ access_token: str
+ token_type: str
+
+
+class TokenData(BaseModel):
+ username: Union[str, None] = None
+ scopes: List[str] = []
+
+
+class User(BaseModel):
+ username: str
+ email: Union[str, None] = None
+ full_name: Union[str, None] = None
+ disabled: Union[bool, None] = None
+
+
+class UserInDB(User):
+ hashed_password: str
+
+
+pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
+
+oauth2_scheme = OAuth2PasswordBearer(
+ tokenUrl="token",
+ scopes={"me": "Read information about the current user.", "items": "Read items."},
+)
+
+app = FastAPI()
+
+
+def verify_password(plain_password, hashed_password):
+ return pwd_context.verify(plain_password, hashed_password)
+
+
+def get_password_hash(password):
+ return pwd_context.hash(password)
+
+
+def get_user(db, username: str):
+ if username in db:
+ user_dict = db[username]
+ return UserInDB(**user_dict)
+
+
+def authenticate_user(fake_db, username: str, password: str):
+ user = get_user(fake_db, username)
+ if not user:
+ return False
+ if not verify_password(password, user.hashed_password):
+ return False
+ return user
+
+
+def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
+ to_encode = data.copy()
+ if expires_delta:
+ expire = datetime.utcnow() + expires_delta
+ else:
+ expire = datetime.utcnow() + timedelta(minutes=15)
+ to_encode.update({"exp": expire})
+ encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
+ return encoded_jwt
+
+
+async def get_current_user(
+ security_scopes: SecurityScopes, token: Annotated[str, Depends(oauth2_scheme)]
+):
+ if security_scopes.scopes:
+ authenticate_value = f'Bearer scope="{security_scopes.scope_str}"'
+ else:
+ authenticate_value = "Bearer"
+ credentials_exception = HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Could not validate credentials",
+ headers={"WWW-Authenticate": authenticate_value},
+ )
+ try:
+ payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
+ username: str = payload.get("sub")
+ if username is None:
+ raise credentials_exception
+ token_scopes = payload.get("scopes", [])
+ token_data = TokenData(scopes=token_scopes, username=username)
+ except (JWTError, ValidationError):
+ raise credentials_exception
+ user = get_user(fake_users_db, username=token_data.username)
+ if user is None:
+ raise credentials_exception
+ for scope in security_scopes.scopes:
+ if scope not in token_data.scopes:
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Not enough permissions",
+ headers={"WWW-Authenticate": authenticate_value},
+ )
+ return user
+
+
+async def get_current_active_user(
+ current_user: Annotated[User, Security(get_current_user, scopes=["me"])]
+):
+ if current_user.disabled:
+ raise HTTPException(status_code=400, detail="Inactive user")
+ return current_user
+
+
+@app.post("/token", response_model=Token)
+async def login_for_access_token(
+ form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
+):
+ user = authenticate_user(fake_users_db, form_data.username, form_data.password)
+ if not user:
+ raise HTTPException(status_code=400, detail="Incorrect username or password")
+ access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
+ access_token = create_access_token(
+ data={"sub": user.username, "scopes": form_data.scopes},
+ expires_delta=access_token_expires,
+ )
+ return {"access_token": access_token, "token_type": "bearer"}
+
+
+@app.get("/users/me/", response_model=User)
+async def read_users_me(
+ current_user: Annotated[User, Depends(get_current_active_user)]
+):
+ return current_user
+
+
+@app.get("/users/me/items/")
+async def read_own_items(
+ current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])]
+):
+ return [{"item_id": "Foo", "owner": current_user.username}]
+
+
+@app.get("/status/")
+async def read_system_status(current_user: Annotated[User, Depends(get_current_user)]):
+ return {"status": "ok"}
diff --git a/docs_src/security/tutorial006_an.py b/docs_src/security/tutorial006_an.py
new file mode 100644
index 000000000..985e4b2ad
--- /dev/null
+++ b/docs_src/security/tutorial006_an.py
@@ -0,0 +1,12 @@
+from fastapi import Depends, FastAPI
+from fastapi.security import HTTPBasic, HTTPBasicCredentials
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+security = HTTPBasic()
+
+
+@app.get("/users/me")
+def read_current_user(credentials: Annotated[HTTPBasicCredentials, Depends(security)]):
+ return {"username": credentials.username, "password": credentials.password}
diff --git a/docs_src/security/tutorial006_an_py39.py b/docs_src/security/tutorial006_an_py39.py
new file mode 100644
index 000000000..03c696a4b
--- /dev/null
+++ b/docs_src/security/tutorial006_an_py39.py
@@ -0,0 +1,13 @@
+from typing import Annotated
+
+from fastapi import Depends, FastAPI
+from fastapi.security import HTTPBasic, HTTPBasicCredentials
+
+app = FastAPI()
+
+security = HTTPBasic()
+
+
+@app.get("/users/me")
+def read_current_user(credentials: Annotated[HTTPBasicCredentials, Depends(security)]):
+ return {"username": credentials.username, "password": credentials.password}
diff --git a/docs_src/security/tutorial007_an.py b/docs_src/security/tutorial007_an.py
new file mode 100644
index 000000000..5fb7c8e57
--- /dev/null
+++ b/docs_src/security/tutorial007_an.py
@@ -0,0 +1,36 @@
+import secrets
+
+from fastapi import Depends, FastAPI, HTTPException, status
+from fastapi.security import HTTPBasic, HTTPBasicCredentials
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+security = HTTPBasic()
+
+
+def get_current_username(
+ credentials: Annotated[HTTPBasicCredentials, Depends(security)]
+):
+ current_username_bytes = credentials.username.encode("utf8")
+ correct_username_bytes = b"stanleyjobson"
+ is_correct_username = secrets.compare_digest(
+ current_username_bytes, correct_username_bytes
+ )
+ current_password_bytes = credentials.password.encode("utf8")
+ correct_password_bytes = b"swordfish"
+ is_correct_password = secrets.compare_digest(
+ current_password_bytes, correct_password_bytes
+ )
+ if not (is_correct_username and is_correct_password):
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Incorrect email or password",
+ headers={"WWW-Authenticate": "Basic"},
+ )
+ return credentials.username
+
+
+@app.get("/users/me")
+def read_current_user(username: Annotated[str, Depends(get_current_username)]):
+ return {"username": username}
diff --git a/docs_src/security/tutorial007_an_py39.py b/docs_src/security/tutorial007_an_py39.py
new file mode 100644
index 000000000..17177dabf
--- /dev/null
+++ b/docs_src/security/tutorial007_an_py39.py
@@ -0,0 +1,36 @@
+import secrets
+from typing import Annotated
+
+from fastapi import Depends, FastAPI, HTTPException, status
+from fastapi.security import HTTPBasic, HTTPBasicCredentials
+
+app = FastAPI()
+
+security = HTTPBasic()
+
+
+def get_current_username(
+ credentials: Annotated[HTTPBasicCredentials, Depends(security)]
+):
+ current_username_bytes = credentials.username.encode("utf8")
+ correct_username_bytes = b"stanleyjobson"
+ is_correct_username = secrets.compare_digest(
+ current_username_bytes, correct_username_bytes
+ )
+ current_password_bytes = credentials.password.encode("utf8")
+ correct_password_bytes = b"swordfish"
+ is_correct_password = secrets.compare_digest(
+ current_password_bytes, correct_password_bytes
+ )
+ if not (is_correct_username and is_correct_password):
+ raise HTTPException(
+ status_code=status.HTTP_401_UNAUTHORIZED,
+ detail="Incorrect email or password",
+ headers={"WWW-Authenticate": "Basic"},
+ )
+ return credentials.username
+
+
+@app.get("/users/me")
+def read_current_user(username: Annotated[str, Depends(get_current_username)]):
+ return {"username": username}
diff --git a/docs_src/settings/app02_an/__init__.py b/docs_src/settings/app02_an/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs_src/settings/app02_an/config.py b/docs_src/settings/app02_an/config.py
new file mode 100644
index 000000000..9a7829135
--- /dev/null
+++ b/docs_src/settings/app02_an/config.py
@@ -0,0 +1,7 @@
+from pydantic import BaseSettings
+
+
+class Settings(BaseSettings):
+ app_name: str = "Awesome API"
+ admin_email: str
+ items_per_user: int = 50
diff --git a/docs_src/settings/app02_an/main.py b/docs_src/settings/app02_an/main.py
new file mode 100644
index 000000000..cb679202d
--- /dev/null
+++ b/docs_src/settings/app02_an/main.py
@@ -0,0 +1,22 @@
+from functools import lru_cache
+
+from fastapi import Depends, FastAPI
+from typing_extensions import Annotated
+
+from .config import Settings
+
+app = FastAPI()
+
+
+@lru_cache()
+def get_settings():
+ return Settings()
+
+
+@app.get("/info")
+async def info(settings: Annotated[Settings, Depends(get_settings)]):
+ return {
+ "app_name": settings.app_name,
+ "admin_email": settings.admin_email,
+ "items_per_user": settings.items_per_user,
+ }
diff --git a/docs_src/settings/app02_an/test_main.py b/docs_src/settings/app02_an/test_main.py
new file mode 100644
index 000000000..7a04d7e8e
--- /dev/null
+++ b/docs_src/settings/app02_an/test_main.py
@@ -0,0 +1,23 @@
+from fastapi.testclient import TestClient
+
+from .config import Settings
+from .main import app, get_settings
+
+client = TestClient(app)
+
+
+def get_settings_override():
+ return Settings(admin_email="testing_admin@example.com")
+
+
+app.dependency_overrides[get_settings] = get_settings_override
+
+
+def test_app():
+ response = client.get("/info")
+ data = response.json()
+ assert data == {
+ "app_name": "Awesome API",
+ "admin_email": "testing_admin@example.com",
+ "items_per_user": 50,
+ }
diff --git a/docs_src/settings/app02_an_py39/__init__.py b/docs_src/settings/app02_an_py39/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs_src/settings/app02_an_py39/config.py b/docs_src/settings/app02_an_py39/config.py
new file mode 100644
index 000000000..9a7829135
--- /dev/null
+++ b/docs_src/settings/app02_an_py39/config.py
@@ -0,0 +1,7 @@
+from pydantic import BaseSettings
+
+
+class Settings(BaseSettings):
+ app_name: str = "Awesome API"
+ admin_email: str
+ items_per_user: int = 50
diff --git a/docs_src/settings/app02_an_py39/main.py b/docs_src/settings/app02_an_py39/main.py
new file mode 100644
index 000000000..61be74fcb
--- /dev/null
+++ b/docs_src/settings/app02_an_py39/main.py
@@ -0,0 +1,22 @@
+from functools import lru_cache
+from typing import Annotated
+
+from fastapi import Depends, FastAPI
+
+from .config import Settings
+
+app = FastAPI()
+
+
+@lru_cache()
+def get_settings():
+ return Settings()
+
+
+@app.get("/info")
+async def info(settings: Annotated[Settings, Depends(get_settings)]):
+ return {
+ "app_name": settings.app_name,
+ "admin_email": settings.admin_email,
+ "items_per_user": settings.items_per_user,
+ }
diff --git a/docs_src/settings/app02_an_py39/test_main.py b/docs_src/settings/app02_an_py39/test_main.py
new file mode 100644
index 000000000..7a04d7e8e
--- /dev/null
+++ b/docs_src/settings/app02_an_py39/test_main.py
@@ -0,0 +1,23 @@
+from fastapi.testclient import TestClient
+
+from .config import Settings
+from .main import app, get_settings
+
+client = TestClient(app)
+
+
+def get_settings_override():
+ return Settings(admin_email="testing_admin@example.com")
+
+
+app.dependency_overrides[get_settings] = get_settings_override
+
+
+def test_app():
+ response = client.get("/info")
+ data = response.json()
+ assert data == {
+ "app_name": "Awesome API",
+ "admin_email": "testing_admin@example.com",
+ "items_per_user": 50,
+ }
diff --git a/docs_src/settings/app03_an/__init__.py b/docs_src/settings/app03_an/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs_src/settings/app03_an/config.py b/docs_src/settings/app03_an/config.py
new file mode 100644
index 000000000..e1c3ee300
--- /dev/null
+++ b/docs_src/settings/app03_an/config.py
@@ -0,0 +1,10 @@
+from pydantic import BaseSettings
+
+
+class Settings(BaseSettings):
+ app_name: str = "Awesome API"
+ admin_email: str
+ items_per_user: int = 50
+
+ class Config:
+ env_file = ".env"
diff --git a/docs_src/settings/app03_an/main.py b/docs_src/settings/app03_an/main.py
new file mode 100644
index 000000000..c33b98f47
--- /dev/null
+++ b/docs_src/settings/app03_an/main.py
@@ -0,0 +1,22 @@
+from functools import lru_cache
+from typing import Annotated
+
+from fastapi import Depends, FastAPI
+
+from . import config
+
+app = FastAPI()
+
+
+@lru_cache()
+def get_settings():
+ return config.Settings()
+
+
+@app.get("/info")
+async def info(settings: Annotated[config.Settings, Depends(get_settings)]):
+ return {
+ "app_name": settings.app_name,
+ "admin_email": settings.admin_email,
+ "items_per_user": settings.items_per_user,
+ }
diff --git a/docs_src/settings/app03_an_py39/__init__.py b/docs_src/settings/app03_an_py39/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/docs_src/settings/app03_an_py39/config.py b/docs_src/settings/app03_an_py39/config.py
new file mode 100644
index 000000000..e1c3ee300
--- /dev/null
+++ b/docs_src/settings/app03_an_py39/config.py
@@ -0,0 +1,10 @@
+from pydantic import BaseSettings
+
+
+class Settings(BaseSettings):
+ app_name: str = "Awesome API"
+ admin_email: str
+ items_per_user: int = 50
+
+ class Config:
+ env_file = ".env"
diff --git a/docs_src/settings/app03_an_py39/main.py b/docs_src/settings/app03_an_py39/main.py
new file mode 100644
index 000000000..b89c6b6cf
--- /dev/null
+++ b/docs_src/settings/app03_an_py39/main.py
@@ -0,0 +1,22 @@
+from functools import lru_cache
+
+from fastapi import Depends, FastAPI
+from typing_extensions import Annotated
+
+from . import config
+
+app = FastAPI()
+
+
+@lru_cache()
+def get_settings():
+ return config.Settings()
+
+
+@app.get("/info")
+async def info(settings: Annotated[config.Settings, Depends(get_settings)]):
+ return {
+ "app_name": settings.app_name,
+ "admin_email": settings.admin_email,
+ "items_per_user": settings.items_per_user,
+ }
diff --git a/docs_src/websockets/tutorial002_an.py b/docs_src/websockets/tutorial002_an.py
new file mode 100644
index 000000000..c838fbd30
--- /dev/null
+++ b/docs_src/websockets/tutorial002_an.py
@@ -0,0 +1,93 @@
+from typing import Union
+
+from fastapi import (
+ Cookie,
+ Depends,
+ FastAPI,
+ Query,
+ WebSocket,
+ WebSocketException,
+ status,
+)
+from fastapi.responses import HTMLResponse
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+html = """
+
+
+
+ Chat
+
+
+ WebSocket Chat
+
+
+
+
+
+"""
+
+
+@app.get("/")
+async def get():
+ return HTMLResponse(html)
+
+
+async def get_cookie_or_token(
+ websocket: WebSocket,
+ session: Annotated[Union[str, None], Cookie()] = None,
+ token: Annotated[Union[str, None], Query()] = None,
+):
+ if session is None and token is None:
+ raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)
+ return session or token
+
+
+@app.websocket("/items/{item_id}/ws")
+async def websocket_endpoint(
+ *,
+ websocket: WebSocket,
+ item_id: str,
+ q: Union[int, None] = None,
+ cookie_or_token: Annotated[str, Depends(get_cookie_or_token)],
+):
+ await websocket.accept()
+ while True:
+ data = await websocket.receive_text()
+ await websocket.send_text(
+ f"Session cookie or query token value is: {cookie_or_token}"
+ )
+ if q is not None:
+ await websocket.send_text(f"Query parameter q is: {q}")
+ await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}")
diff --git a/docs_src/websockets/tutorial002_an_py310.py b/docs_src/websockets/tutorial002_an_py310.py
new file mode 100644
index 000000000..551539b32
--- /dev/null
+++ b/docs_src/websockets/tutorial002_an_py310.py
@@ -0,0 +1,92 @@
+from typing import Annotated
+
+from fastapi import (
+ Cookie,
+ Depends,
+ FastAPI,
+ Query,
+ WebSocket,
+ WebSocketException,
+ status,
+)
+from fastapi.responses import HTMLResponse
+
+app = FastAPI()
+
+html = """
+
+
+
+ Chat
+
+
+ WebSocket Chat
+
+
+
+
+
+"""
+
+
+@app.get("/")
+async def get():
+ return HTMLResponse(html)
+
+
+async def get_cookie_or_token(
+ websocket: WebSocket,
+ session: Annotated[str | None, Cookie()] = None,
+ token: Annotated[str | None, Query()] = None,
+):
+ if session is None and token is None:
+ raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)
+ return session or token
+
+
+@app.websocket("/items/{item_id}/ws")
+async def websocket_endpoint(
+ *,
+ websocket: WebSocket,
+ item_id: str,
+ q: int | None = None,
+ cookie_or_token: Annotated[str, Depends(get_cookie_or_token)],
+):
+ await websocket.accept()
+ while True:
+ data = await websocket.receive_text()
+ await websocket.send_text(
+ f"Session cookie or query token value is: {cookie_or_token}"
+ )
+ if q is not None:
+ await websocket.send_text(f"Query parameter q is: {q}")
+ await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}")
diff --git a/docs_src/websockets/tutorial002_an_py39.py b/docs_src/websockets/tutorial002_an_py39.py
new file mode 100644
index 000000000..606d355fe
--- /dev/null
+++ b/docs_src/websockets/tutorial002_an_py39.py
@@ -0,0 +1,92 @@
+from typing import Annotated, Union
+
+from fastapi import (
+ Cookie,
+ Depends,
+ FastAPI,
+ Query,
+ WebSocket,
+ WebSocketException,
+ status,
+)
+from fastapi.responses import HTMLResponse
+
+app = FastAPI()
+
+html = """
+
+
+
+ Chat
+
+
+ WebSocket Chat
+
+
+
+
+
+"""
+
+
+@app.get("/")
+async def get():
+ return HTMLResponse(html)
+
+
+async def get_cookie_or_token(
+ websocket: WebSocket,
+ session: Annotated[Union[str, None], Cookie()] = None,
+ token: Annotated[Union[str, None], Query()] = None,
+):
+ if session is None and token is None:
+ raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)
+ return session or token
+
+
+@app.websocket("/items/{item_id}/ws")
+async def websocket_endpoint(
+ *,
+ websocket: WebSocket,
+ item_id: str,
+ q: Union[int, None] = None,
+ cookie_or_token: Annotated[str, Depends(get_cookie_or_token)],
+):
+ await websocket.accept()
+ while True:
+ data = await websocket.receive_text()
+ await websocket.send_text(
+ f"Session cookie or query token value is: {cookie_or_token}"
+ )
+ if q is not None:
+ await websocket.send_text(f"Query parameter q is: {q}")
+ await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}")
diff --git a/docs_src/websockets/tutorial002_py310.py b/docs_src/websockets/tutorial002_py310.py
new file mode 100644
index 000000000..51daf58e5
--- /dev/null
+++ b/docs_src/websockets/tutorial002_py310.py
@@ -0,0 +1,89 @@
+from fastapi import (
+ Cookie,
+ Depends,
+ FastAPI,
+ Query,
+ WebSocket,
+ WebSocketException,
+ status,
+)
+from fastapi.responses import HTMLResponse
+
+app = FastAPI()
+
+html = """
+
+
+
+ Chat
+
+
+ WebSocket Chat
+
+
+
+
+
+"""
+
+
+@app.get("/")
+async def get():
+ return HTMLResponse(html)
+
+
+async def get_cookie_or_token(
+ websocket: WebSocket,
+ session: str | None = Cookie(default=None),
+ token: str | None = Query(default=None),
+):
+ if session is None and token is None:
+ raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)
+ return session or token
+
+
+@app.websocket("/items/{item_id}/ws")
+async def websocket_endpoint(
+ websocket: WebSocket,
+ item_id: str,
+ q: int | None = None,
+ cookie_or_token: str = Depends(get_cookie_or_token),
+):
+ await websocket.accept()
+ while True:
+ data = await websocket.receive_text()
+ await websocket.send_text(
+ f"Session cookie or query token value is: {cookie_or_token}"
+ )
+ if q is not None:
+ await websocket.send_text(f"Query parameter q is: {q}")
+ await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}")
diff --git a/docs_src/websockets/tutorial003_py39.py b/docs_src/websockets/tutorial003_py39.py
new file mode 100644
index 000000000..316218088
--- /dev/null
+++ b/docs_src/websockets/tutorial003_py39.py
@@ -0,0 +1,81 @@
+from fastapi import FastAPI, WebSocket, WebSocketDisconnect
+from fastapi.responses import HTMLResponse
+
+app = FastAPI()
+
+html = """
+
+
+
+ Chat
+
+
+ WebSocket Chat
+ Your ID:
+
+
+
+
+
+"""
+
+
+class ConnectionManager:
+ def __init__(self):
+ self.active_connections: list[WebSocket] = []
+
+ async def connect(self, websocket: WebSocket):
+ await websocket.accept()
+ self.active_connections.append(websocket)
+
+ def disconnect(self, websocket: WebSocket):
+ self.active_connections.remove(websocket)
+
+ async def send_personal_message(self, message: str, websocket: WebSocket):
+ await websocket.send_text(message)
+
+ async def broadcast(self, message: str):
+ for connection in self.active_connections:
+ await connection.send_text(message)
+
+
+manager = ConnectionManager()
+
+
+@app.get("/")
+async def get():
+ return HTMLResponse(html)
+
+
+@app.websocket("/ws/{client_id}")
+async def websocket_endpoint(websocket: WebSocket, client_id: int):
+ await manager.connect(websocket)
+ try:
+ while True:
+ data = await websocket.receive_text()
+ await manager.send_personal_message(f"You wrote: {data}", websocket)
+ await manager.broadcast(f"Client #{client_id} says: {data}")
+ except WebSocketDisconnect:
+ manager.disconnect(websocket)
+ await manager.broadcast(f"Client #{client_id} left the chat")
diff --git a/fastapi/__init__.py b/fastapi/__init__.py
index 037d9804b..e1c2be990 100644
--- a/fastapi/__init__.py
+++ b/fastapi/__init__.py
@@ -1,6 +1,6 @@
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
-__version__ = "0.88.0"
+__version__ = "0.95.1"
from starlette import status as status
diff --git a/fastapi/applications.py b/fastapi/applications.py
index 61d4582d2..8b3a74d3c 100644
--- a/fastapi/applications.py
+++ b/fastapi/applications.py
@@ -9,6 +9,7 @@ from typing import (
Optional,
Sequence,
Type,
+ TypeVar,
Union,
)
@@ -35,17 +36,20 @@ from starlette.applications import Starlette
from starlette.datastructures import State
from starlette.exceptions import HTTPException
from starlette.middleware import Middleware
+from starlette.middleware.base import BaseHTTPMiddleware
from starlette.middleware.errors import ServerErrorMiddleware
from starlette.middleware.exceptions import ExceptionMiddleware
from starlette.requests import Request
from starlette.responses import HTMLResponse, JSONResponse, Response
from starlette.routing import BaseRoute
-from starlette.types import ASGIApp, Receive, Scope, Send
+from starlette.types import ASGIApp, Lifespan, Receive, Scope, Send
+
+AppType = TypeVar("AppType", bound="FastAPI")
class FastAPI(Starlette):
def __init__(
- self,
+ self: AppType,
*,
debug: bool = False,
routes: Optional[List[BaseRoute]] = None,
@@ -70,6 +74,7 @@ class FastAPI(Starlette):
] = None,
on_startup: Optional[Sequence[Callable[[], Any]]] = None,
on_shutdown: Optional[Sequence[Callable[[], Any]]] = None,
+ lifespan: Optional[Lifespan[AppType]] = None,
terms_of_service: Optional[str] = None,
contact: Optional[Dict[str, Union[str, Any]]] = None,
license_info: Optional[Dict[str, Union[str, Any]]] = None,
@@ -86,7 +91,7 @@ class FastAPI(Starlette):
),
**extra: Any,
) -> None:
- self._debug: bool = debug
+ self.debug = debug
self.title = title
self.description = description
self.version = version
@@ -124,6 +129,7 @@ class FastAPI(Starlette):
dependency_overrides_provider=self,
on_startup=on_startup,
on_shutdown=on_shutdown,
+ lifespan=lifespan,
default_response_class=default_response_class,
dependencies=dependencies,
callbacks=callbacks,
@@ -143,7 +149,7 @@ class FastAPI(Starlette):
self.user_middleware: List[Middleware] = (
[] if middleware is None else list(middleware)
)
- self.middleware_stack: ASGIApp = self.build_middleware_stack()
+ self.middleware_stack: Union[ASGIApp, None] = None
self.setup()
def build_middleware_stack(self) -> ASGIApp:
@@ -274,7 +280,7 @@ class FastAPI(Starlette):
path: str,
endpoint: Callable[..., Coroutine[Any, Any, Response]],
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[Depends]] = None,
@@ -332,7 +338,7 @@ class FastAPI(Starlette):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[Depends]] = None,
@@ -435,7 +441,7 @@ class FastAPI(Starlette):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[Depends]] = None,
@@ -490,7 +496,7 @@ class FastAPI(Starlette):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[Depends]] = None,
@@ -545,7 +551,7 @@ class FastAPI(Starlette):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[Depends]] = None,
@@ -600,7 +606,7 @@ class FastAPI(Starlette):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[Depends]] = None,
@@ -655,7 +661,7 @@ class FastAPI(Starlette):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[Depends]] = None,
@@ -710,7 +716,7 @@ class FastAPI(Starlette):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[Depends]] = None,
@@ -765,7 +771,7 @@ class FastAPI(Starlette):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[Depends]] = None,
@@ -820,7 +826,7 @@ class FastAPI(Starlette):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[Depends]] = None,
@@ -870,3 +876,35 @@ class FastAPI(Starlette):
openapi_extra=openapi_extra,
generate_unique_id_function=generate_unique_id_function,
)
+
+ def websocket_route(
+ self, path: str, name: Union[str, None] = None
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.router.add_websocket_route(path, func, name=name)
+ return func
+
+ return decorator
+
+ def on_event(
+ self, event_type: str
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ return self.router.on_event(event_type)
+
+ def middleware(
+ self, middleware_type: str
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.add_middleware(BaseHTTPMiddleware, dispatch=func)
+ return func
+
+ return decorator
+
+ def exception_handler(
+ self, exc_class_or_status_code: Union[int, Type[Exception]]
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.add_exception_handler(exc_class_or_status_code, func)
+ return func
+
+ return decorator
diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py
index b2aff9438..b12bb5026 100644
--- a/fastapi/dependencies/utils.py
+++ b/fastapi/dependencies/utils.py
@@ -1,7 +1,7 @@
import dataclasses
import inspect
from contextlib import contextmanager
-from copy import deepcopy
+from copy import copy, deepcopy
from typing import (
Any,
Callable,
@@ -49,7 +49,7 @@ from pydantic.fields import (
Undefined,
)
from pydantic.schema import get_annotation_from_field_info
-from pydantic.typing import evaluate_forwardref
+from pydantic.typing import evaluate_forwardref, get_args, get_origin
from pydantic.utils import lenient_issubclass
from starlette.background import BackgroundTasks
from starlette.concurrency import run_in_threadpool
@@ -57,6 +57,7 @@ from starlette.datastructures import FormData, Headers, QueryParams, UploadFile
from starlette.requests import HTTPConnection, Request
from starlette.responses import Response
from starlette.websockets import WebSocket
+from typing_extensions import Annotated
sequence_shapes = {
SHAPE_LIST,
@@ -112,18 +113,18 @@ def check_file_field(field: ModelField) -> None:
def get_param_sub_dependant(
- *, param: inspect.Parameter, path: str, security_scopes: Optional[List[str]] = None
+ *,
+ param_name: str,
+ depends: params.Depends,
+ path: str,
+ security_scopes: Optional[List[str]] = None,
) -> Dependant:
- depends: params.Depends = param.default
- if depends.dependency:
- dependency = depends.dependency
- else:
- dependency = param.annotation
+ assert depends.dependency
return get_sub_dependant(
depends=depends,
- dependency=dependency,
+ dependency=depends.dependency,
path=path,
- name=param.name,
+ name=param_name,
security_scopes=security_scopes,
)
@@ -253,7 +254,7 @@ def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
name=param.name,
kind=param.kind,
default=param.default,
- annotation=get_typed_annotation(param, globalns),
+ annotation=get_typed_annotation(param.annotation, globalns),
)
for param in signature.parameters.values()
]
@@ -261,14 +262,24 @@ def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
return typed_signature
-def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> Any:
- annotation = param.annotation
+def get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any:
if isinstance(annotation, str):
annotation = ForwardRef(annotation)
annotation = evaluate_forwardref(annotation, globalns, globalns)
return annotation
+def get_typed_return_annotation(call: Callable[..., Any]) -> Any:
+ signature = inspect.signature(call)
+ annotation = signature.return_annotation
+
+ if annotation is inspect.Signature.empty:
+ return None
+
+ globalns = getattr(call, "__globals__", {})
+ return get_typed_annotation(annotation, globalns)
+
+
def get_dependant(
*,
path: str,
@@ -288,122 +299,200 @@ def get_dependant(
use_cache=use_cache,
)
for param_name, param in signature_params.items():
- if isinstance(param.default, params.Depends):
+ is_path_param = param_name in path_param_names
+ type_annotation, depends, param_field = analyze_param(
+ param_name=param_name,
+ annotation=param.annotation,
+ value=param.default,
+ is_path_param=is_path_param,
+ )
+ if depends is not None:
sub_dependant = get_param_sub_dependant(
- param=param, path=path, security_scopes=security_scopes
+ param_name=param_name,
+ depends=depends,
+ path=path,
+ security_scopes=security_scopes,
)
dependant.dependencies.append(sub_dependant)
continue
- if add_non_field_param_to_dependency(param=param, dependant=dependant):
+ if add_non_field_param_to_dependency(
+ param_name=param_name,
+ type_annotation=type_annotation,
+ dependant=dependant,
+ ):
+ assert (
+ param_field is None
+ ), f"Cannot specify multiple FastAPI annotations for {param_name!r}"
continue
- param_field = get_param_field(
- param=param, default_field_info=params.Query, param_name=param_name
- )
- if param_name in path_param_names:
- assert is_scalar_field(
- field=param_field
- ), "Path params must be of one of the supported types"
- ignore_default = not isinstance(param.default, params.Path)
- param_field = get_param_field(
- param=param,
- param_name=param_name,
- default_field_info=params.Path,
- force_type=params.ParamTypes.path,
- ignore_default=ignore_default,
- )
- add_param_to_fields(field=param_field, dependant=dependant)
- elif is_scalar_field(field=param_field):
- add_param_to_fields(field=param_field, dependant=dependant)
- elif isinstance(
- param.default, (params.Query, params.Header)
- ) and is_scalar_sequence_field(param_field):
- add_param_to_fields(field=param_field, dependant=dependant)
- else:
- field_info = param_field.field_info
- assert isinstance(
- field_info, params.Body
- ), f"Param: {param_field.name} can only be a request body, using Body()"
+ assert param_field is not None
+ if is_body_param(param_field=param_field, is_path_param=is_path_param):
dependant.body_params.append(param_field)
+ else:
+ add_param_to_fields(field=param_field, dependant=dependant)
return dependant
def add_non_field_param_to_dependency(
- *, param: inspect.Parameter, dependant: Dependant
+ *, param_name: str, type_annotation: Any, dependant: Dependant
) -> Optional[bool]:
- if lenient_issubclass(param.annotation, Request):
- dependant.request_param_name = param.name
+ if lenient_issubclass(type_annotation, Request):
+ dependant.request_param_name = param_name
return True
- elif lenient_issubclass(param.annotation, WebSocket):
- dependant.websocket_param_name = param.name
+ elif lenient_issubclass(type_annotation, WebSocket):
+ dependant.websocket_param_name = param_name
return True
- elif lenient_issubclass(param.annotation, HTTPConnection):
- dependant.http_connection_param_name = param.name
+ elif lenient_issubclass(type_annotation, HTTPConnection):
+ dependant.http_connection_param_name = param_name
return True
- elif lenient_issubclass(param.annotation, Response):
- dependant.response_param_name = param.name
+ elif lenient_issubclass(type_annotation, Response):
+ dependant.response_param_name = param_name
return True
- elif lenient_issubclass(param.annotation, BackgroundTasks):
- dependant.background_tasks_param_name = param.name
+ elif lenient_issubclass(type_annotation, BackgroundTasks):
+ dependant.background_tasks_param_name = param_name
return True
- elif lenient_issubclass(param.annotation, SecurityScopes):
- dependant.security_scopes_param_name = param.name
+ elif lenient_issubclass(type_annotation, SecurityScopes):
+ dependant.security_scopes_param_name = param_name
return True
return None
-def get_param_field(
+def analyze_param(
*,
- param: inspect.Parameter,
param_name: str,
- default_field_info: Type[params.Param] = params.Param,
- force_type: Optional[params.ParamTypes] = None,
- ignore_default: bool = False,
-) -> ModelField:
- default_value: Any = Undefined
- had_schema = False
- if not param.default == param.empty and ignore_default is False:
- default_value = param.default
- if isinstance(default_value, FieldInfo):
- had_schema = True
- field_info = default_value
- default_value = field_info.default
- if (
+ annotation: Any,
+ value: Any,
+ is_path_param: bool,
+) -> Tuple[Any, Optional[params.Depends], Optional[ModelField]]:
+ field_info = None
+ used_default_field_info = False
+ depends = None
+ type_annotation: Any = Any
+ if (
+ annotation is not inspect.Signature.empty
+ and get_origin(annotation) is Annotated # type: ignore[comparison-overlap]
+ ):
+ annotated_args = get_args(annotation)
+ type_annotation = annotated_args[0]
+ fastapi_annotations = [
+ arg
+ for arg in annotated_args[1:]
+ if isinstance(arg, (FieldInfo, params.Depends))
+ ]
+ assert (
+ len(fastapi_annotations) <= 1
+ ), f"Cannot specify multiple `Annotated` FastAPI arguments for {param_name!r}"
+ fastapi_annotation = next(iter(fastapi_annotations), None)
+ if isinstance(fastapi_annotation, FieldInfo):
+ # Copy `field_info` because we mutate `field_info.default` below.
+ field_info = copy(fastapi_annotation)
+ assert field_info.default is Undefined or field_info.default is Required, (
+ f"`{field_info.__class__.__name__}` default value cannot be set in"
+ f" `Annotated` for {param_name!r}. Set the default value with `=` instead."
+ )
+ if value is not inspect.Signature.empty:
+ assert not is_path_param, "Path parameters cannot have default values"
+ field_info.default = value
+ else:
+ field_info.default = Required
+ elif isinstance(fastapi_annotation, params.Depends):
+ depends = fastapi_annotation
+ elif annotation is not inspect.Signature.empty:
+ type_annotation = annotation
+
+ if isinstance(value, params.Depends):
+ assert depends is None, (
+ "Cannot specify `Depends` in `Annotated` and default value"
+ f" together for {param_name!r}"
+ )
+ assert field_info is None, (
+ "Cannot specify a FastAPI annotation in `Annotated` and `Depends` as a"
+ f" default value together for {param_name!r}"
+ )
+ depends = value
+ elif isinstance(value, FieldInfo):
+ assert field_info is None, (
+ "Cannot specify FastAPI annotations in `Annotated` and default value"
+ f" together for {param_name!r}"
+ )
+ field_info = value
+
+ if depends is not None and depends.dependency is None:
+ depends.dependency = type_annotation
+
+ if lenient_issubclass(
+ type_annotation,
+ (Request, WebSocket, HTTPConnection, Response, BackgroundTasks, SecurityScopes),
+ ):
+ assert depends is None, f"Cannot specify `Depends` for type {type_annotation!r}"
+ assert (
+ field_info is None
+ ), f"Cannot specify FastAPI annotation for type {type_annotation!r}"
+ elif field_info is None and depends is None:
+ default_value = value if value is not inspect.Signature.empty else Required
+ if is_path_param:
+ # We might check here that `default_value is Required`, but the fact is that the same
+ # parameter might sometimes be a path parameter and sometimes not. See
+ # `tests/test_infer_param_optionality.py` for an example.
+ field_info = params.Path()
+ else:
+ field_info = params.Query(default=default_value)
+ used_default_field_info = True
+
+ field = None
+ if field_info is not None:
+ if is_path_param:
+ assert isinstance(field_info, params.Path), (
+ f"Cannot use `{field_info.__class__.__name__}` for path param"
+ f" {param_name!r}"
+ )
+ elif (
isinstance(field_info, params.Param)
and getattr(field_info, "in_", None) is None
):
- field_info.in_ = default_field_info.in_
- if force_type:
- field_info.in_ = force_type # type: ignore
- else:
- field_info = default_field_info(default=default_value)
- required = True
- if default_value is Required or ignore_default:
- required = True
- default_value = None
- elif default_value is not Undefined:
- required = False
- annotation: Any = Any
- if not param.annotation == param.empty:
- annotation = param.annotation
- annotation = get_annotation_from_field_info(annotation, field_info, param_name)
- if not field_info.alias and getattr(field_info, "convert_underscores", None):
- alias = param.name.replace("_", "-")
- else:
- alias = field_info.alias or param.name
- field = create_response_field(
- name=param.name,
- type_=annotation,
- default=default_value,
- alias=alias,
- required=required,
- field_info=field_info,
- )
- if not had_schema and not is_scalar_field(field=field):
- field.field_info = params.Body(field_info.default)
- if not had_schema and lenient_issubclass(field.type_, UploadFile):
- field.field_info = params.File(field_info.default)
+ field_info.in_ = params.ParamTypes.query
+ annotation = get_annotation_from_field_info(
+ annotation if annotation is not inspect.Signature.empty else Any,
+ field_info,
+ param_name,
+ )
+ if not field_info.alias and getattr(field_info, "convert_underscores", None):
+ alias = param_name.replace("_", "-")
+ else:
+ alias = field_info.alias or param_name
+ field = create_response_field(
+ name=param_name,
+ type_=annotation,
+ default=field_info.default,
+ alias=alias,
+ required=field_info.default in (Required, Undefined),
+ field_info=field_info,
+ )
+ if used_default_field_info:
+ if lenient_issubclass(field.type_, UploadFile):
+ field.field_info = params.File(field_info.default)
+ elif not is_scalar_field(field=field):
+ field.field_info = params.Body(field_info.default)
+
+ return type_annotation, depends, field
+
- return field
+def is_body_param(*, param_field: ModelField, is_path_param: bool) -> bool:
+ if is_path_param:
+ assert is_scalar_field(
+ field=param_field
+ ), "Path params must be of one of the supported types"
+ return False
+ elif is_scalar_field(field=param_field):
+ return False
+ elif isinstance(
+ param_field.field_info, (params.Query, params.Header)
+ ) and is_scalar_sequence_field(param_field):
+ return False
+ else:
+ assert isinstance(
+ param_field.field_info, params.Body
+ ), f"Param: {param_field.name} can only be a request body, using Body()"
+ return True
def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None:
@@ -686,7 +775,7 @@ async def request_body_to_args(
fn: Callable[[], Coroutine[Any, Any, Any]]
) -> None:
result = await fn()
- results.append(result)
+ results.append(result) # noqa: B023
async with anyio.create_task_group() as tg:
for sub_value in value:
diff --git a/fastapi/param_functions.py b/fastapi/param_functions.py
index 1932ef065..75f054e9d 100644
--- a/fastapi/param_functions.py
+++ b/fastapi/param_functions.py
@@ -5,7 +5,7 @@ from pydantic.fields import Undefined
def Path( # noqa: N802
- default: Any = Undefined,
+ default: Any = ...,
*,
alias: Optional[str] = None,
title: Optional[str] = None,
diff --git a/fastapi/params.py b/fastapi/params.py
index 5395b98a3..16c5c309a 100644
--- a/fastapi/params.py
+++ b/fastapi/params.py
@@ -62,7 +62,7 @@ class Path(Param):
def __init__(
self,
- default: Any = Undefined,
+ default: Any = ...,
*,
alias: Optional[str] = None,
title: Optional[str] = None,
@@ -80,9 +80,10 @@ class Path(Param):
include_in_schema: bool = True,
**extra: Any,
):
+ assert default is ..., "Path parameters cannot have a default value"
self.in_ = self.in_
super().__init__(
- default=...,
+ default=default,
alias=alias,
title=title,
description=description,
@@ -279,7 +280,7 @@ class Body(FieldInfo):
class Form(Body):
def __init__(
self,
- default: Any,
+ default: Any = Undefined,
*,
media_type: str = "application/x-www-form-urlencoded",
alias: Optional[str] = None,
@@ -319,7 +320,7 @@ class Form(Body):
class File(Form):
def __init__(
self,
- default: Any,
+ default: Any = Undefined,
*,
media_type: str = "multipart/form-data",
alias: Optional[str] = None,
diff --git a/fastapi/routing.py b/fastapi/routing.py
index 593bb9495..ed3279cb2 100644
--- a/fastapi/routing.py
+++ b/fastapi/routing.py
@@ -27,6 +27,7 @@ from fastapi.dependencies.utils import (
get_dependant,
get_parameterless_sub_dependant,
get_path_hash_val,
+ get_typed_return_annotation,
solve_dependencies,
)
from fastapi.encoders import DictIntStrAny, SetIntStr, jsonable_encoder
@@ -46,6 +47,7 @@ from fastapi.utils import (
from pydantic import BaseModel
from pydantic.error_wrappers import ErrorWrapper, ValidationError
from pydantic.fields import ModelField, Undefined
+from pydantic.utils import lenient_issubclass
from starlette import routing
from starlette.concurrency import run_in_threadpool
from starlette.exceptions import HTTPException
@@ -60,7 +62,7 @@ from starlette.routing import (
websocket_session,
)
from starlette.status import WS_1008_POLICY_VIOLATION
-from starlette.types import ASGIApp, Scope
+from starlette.types import ASGIApp, Lifespan, Scope
from starlette.websockets import WebSocket
@@ -328,7 +330,7 @@ class APIRoute(routing.Route):
path: str,
endpoint: Callable[..., Any],
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
@@ -359,6 +361,12 @@ class APIRoute(routing.Route):
) -> None:
self.path = path
self.endpoint = endpoint
+ if isinstance(response_model, DefaultPlaceholder):
+ return_annotation = get_typed_return_annotation(endpoint)
+ if lenient_issubclass(return_annotation, Response):
+ response_model = None
+ else:
+ response_model = return_annotation
self.response_model = response_model
self.summary = summary
self.response_description = response_description
@@ -490,6 +498,9 @@ class APIRouter(routing.Router):
route_class: Type[APIRoute] = APIRoute,
on_startup: Optional[Sequence[Callable[[], Any]]] = None,
on_shutdown: Optional[Sequence[Callable[[], Any]]] = None,
+ # the generic to Lifespan[AppType] is the type of the top level application
+ # which the router cannot know statically, so we use typing.Any
+ lifespan: Optional[Lifespan[Any]] = None,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
generate_unique_id_function: Callable[[APIRoute], str] = Default(
@@ -502,6 +513,7 @@ class APIRouter(routing.Router):
default=default,
on_startup=on_startup,
on_shutdown=on_shutdown,
+ lifespan=lifespan,
)
if prefix:
assert prefix.startswith("/"), "A path prefix must start with '/'"
@@ -521,12 +533,31 @@ class APIRouter(routing.Router):
self.generate_unique_id_function = generate_unique_id_function
self.added_routes: Set[str] = set()
+ def route(
+ self,
+ path: str,
+ methods: Optional[List[str]] = None,
+ name: Optional[str] = None,
+ include_in_schema: bool = True,
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.add_route(
+ path,
+ func,
+ methods=methods,
+ name=name,
+ include_in_schema=include_in_schema,
+ )
+ return func
+
+ return decorator
+
def add_api_route(
self,
path: str,
endpoint: Callable[..., Any],
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
@@ -610,7 +641,7 @@ class APIRouter(routing.Router):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
@@ -692,6 +723,15 @@ class APIRouter(routing.Router):
return decorator
+ def websocket_route(
+ self, path: str, name: Union[str, None] = None
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.add_websocket_route(path, func, name=name)
+ return func
+
+ return decorator
+
def include_router(
self,
router: "APIRouter",
@@ -813,7 +853,7 @@ class APIRouter(routing.Router):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
@@ -869,7 +909,7 @@ class APIRouter(routing.Router):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
@@ -925,7 +965,7 @@ class APIRouter(routing.Router):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
@@ -981,7 +1021,7 @@ class APIRouter(routing.Router):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
@@ -1037,7 +1077,7 @@ class APIRouter(routing.Router):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
@@ -1093,7 +1133,7 @@ class APIRouter(routing.Router):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
@@ -1149,7 +1189,7 @@ class APIRouter(routing.Router):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
@@ -1205,7 +1245,7 @@ class APIRouter(routing.Router):
self,
path: str,
*,
- response_model: Any = None,
+ response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
@@ -1230,7 +1270,6 @@ class APIRouter(routing.Router):
generate_unique_id
),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
-
return self.api_route(
path=path,
response_model=response_model,
@@ -1257,3 +1296,12 @@ class APIRouter(routing.Router):
openapi_extra=openapi_extra,
generate_unique_id_function=generate_unique_id_function,
)
+
+ def on_event(
+ self, event_type: str
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.add_event_handler(event_type, func)
+ return func
+
+ return decorator
diff --git a/fastapi/security/api_key.py b/fastapi/security/api_key.py
index 24ddbf482..61730187a 100644
--- a/fastapi/security/api_key.py
+++ b/fastapi/security/api_key.py
@@ -18,7 +18,7 @@ class APIKeyQuery(APIKeyBase):
name: str,
scheme_name: Optional[str] = None,
description: Optional[str] = None,
- auto_error: bool = True
+ auto_error: bool = True,
):
self.model: APIKey = APIKey(
**{"in": APIKeyIn.query}, name=name, description=description
@@ -45,7 +45,7 @@ class APIKeyHeader(APIKeyBase):
name: str,
scheme_name: Optional[str] = None,
description: Optional[str] = None,
- auto_error: bool = True
+ auto_error: bool = True,
):
self.model: APIKey = APIKey(
**{"in": APIKeyIn.header}, name=name, description=description
@@ -72,7 +72,7 @@ class APIKeyCookie(APIKeyBase):
name: str,
scheme_name: Optional[str] = None,
description: Optional[str] = None,
- auto_error: bool = True
+ auto_error: bool = True,
):
self.model: APIKey = APIKey(
**{"in": APIKeyIn.cookie}, name=name, description=description
diff --git a/fastapi/security/oauth2.py b/fastapi/security/oauth2.py
index eb6b4277c..dc75dc9fe 100644
--- a/fastapi/security/oauth2.py
+++ b/fastapi/security/oauth2.py
@@ -119,7 +119,7 @@ class OAuth2(SecurityBase):
flows: Union[OAuthFlowsModel, Dict[str, Dict[str, Any]]] = OAuthFlowsModel(),
scheme_name: Optional[str] = None,
description: Optional[str] = None,
- auto_error: bool = True
+ auto_error: bool = True,
):
self.model = OAuth2Model(flows=flows, description=description)
self.scheme_name = scheme_name or self.__class__.__name__
diff --git a/fastapi/security/open_id_connect_url.py b/fastapi/security/open_id_connect_url.py
index 393614f7c..4e65f1f6c 100644
--- a/fastapi/security/open_id_connect_url.py
+++ b/fastapi/security/open_id_connect_url.py
@@ -14,7 +14,7 @@ class OpenIdConnect(SecurityBase):
openIdConnectUrl: str,
scheme_name: Optional[str] = None,
description: Optional[str] = None,
- auto_error: bool = True
+ auto_error: bool = True,
):
self.model = OpenIdConnectModel(
openIdConnectUrl=openIdConnectUrl, description=description
diff --git a/fastapi/utils.py b/fastapi/utils.py
index b15f6a2cf..d8be53c57 100644
--- a/fastapi/utils.py
+++ b/fastapi/utils.py
@@ -1,4 +1,3 @@
-import functools
import re
import warnings
from dataclasses import is_dataclass
@@ -73,22 +72,26 @@ def create_response_field(
class_validators = class_validators or {}
field_info = field_info or FieldInfo()
- response_field = functools.partial(
- ModelField,
- name=name,
- type_=type_,
- class_validators=class_validators,
- default=default,
- required=required,
- model_config=model_config,
- alias=alias,
- )
-
try:
- return response_field(field_info=field_info)
+ return ModelField(
+ name=name,
+ type_=type_,
+ class_validators=class_validators,
+ default=default,
+ required=required,
+ model_config=model_config,
+ alias=alias,
+ field_info=field_info,
+ )
except RuntimeError:
raise fastapi.exceptions.FastAPIError(
- f"Invalid args for response field! Hint: check that {type_} is a valid pydantic field type"
+ "Invalid args for response field! Hint: "
+ f"check that {type_} is a valid Pydantic field type. "
+ "If you are using a return type annotation that is not a valid Pydantic "
+ "field (e.g. Union[Response, dict, None]) you can disable generating the "
+ "response model from the type annotation with the path operation decorator "
+ "parameter response_model=None. Read more: "
+ "https://fastapi.tiangolo.com/tutorial/response-model/"
) from None
diff --git a/pyproject.toml b/pyproject.toml
index be3080ae8..6aa095a64 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -27,6 +27,8 @@ classifiers = [
"Environment :: Web Environment",
"Framework :: AsyncIO",
"Framework :: FastAPI",
+ "Framework :: Pydantic",
+ "Framework :: Pydantic :: 1",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3 :: Only",
@@ -39,7 +41,7 @@ classifiers = [
"Topic :: Internet :: WWW/HTTP",
]
dependencies = [
- "starlette==0.22.0",
+ "starlette>=0.26.1,<0.27.0",
"pydantic >=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0",
]
dynamic = ["version"]
@@ -51,21 +53,21 @@ Documentation = "https://fastapi.tiangolo.com/"
[project.optional-dependencies]
test = [
"pytest >=7.1.3,<8.0.0",
- "coverage[toml] >= 6.5.0,<7.0",
+ "coverage[toml] >= 6.5.0,< 8.0",
"mypy ==0.982",
"ruff ==0.0.138",
- "black == 22.10.0",
+ "black == 23.1.0",
"isort >=5.0.6,<6.0.0",
"httpx >=0.23.0,<0.24.0",
"email_validator >=1.1.1,<2.0.0",
# TODO: once removing databases from tutorial, upgrade SQLAlchemy
# probably when including SQLModel
- "sqlalchemy >=1.3.18,<=1.4.41",
+ "sqlalchemy >=1.3.18,<1.4.43",
"peewee >=3.13.3,<4.0.0",
"databases[sqlite] >=0.3.2,<0.7.0",
"orjson >=3.2.1,<4.0.0",
"ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0",
- "python-multipart >=0.0.5,<0.0.6",
+ "python-multipart >=0.0.5,<0.0.7",
"flask >=1.1.2,<3.0.0",
"anyio[trio] >=3.2.1,<4.0.0",
"python-jose[cryptography] >=3.3.0,<4.0.0",
@@ -73,7 +75,7 @@ test = [
"passlib[bcrypt] >=1.7.2,<2.0.0",
# types
- "types-ujson ==5.5.0",
+ "types-ujson ==5.7.0.1",
"types-orjson ==3.6.2",
]
doc = [
@@ -81,14 +83,13 @@ doc = [
"mkdocs-material >=8.1.4,<9.0.0",
"mdx-include >=1.4.1,<2.0.0",
"mkdocs-markdownextradata-plugin >=0.1.7,<0.3.0",
- # TODO: upgrade and enable typer-cli once it supports Click 8.x.x
- # "typer-cli >=0.0.12,<0.0.13",
+ "typer-cli >=0.0.13,<0.0.14",
"typer[all] >=0.6.1,<0.8.0",
"pyyaml >=5.3.1,<7.0.0",
]
dev = [
"ruff ==0.0.138",
- "uvicorn[standard] >=0.12.0,<0.19.0",
+ "uvicorn[standard] >=0.12.0,<0.21.0",
"pre-commit >=2.17.0,<3.0.0",
]
all = [
@@ -155,6 +156,10 @@ source = [
"fastapi"
]
context = '${CONTEXT}'
+omit = [
+ "docs_src/response_model/tutorial003_04.py",
+ "docs_src/response_model/tutorial003_04_py310.py",
+]
[tool.ruff]
select = [
@@ -181,6 +186,12 @@ ignore = [
"docs_src/dataclasses/tutorial003.py" = ["I001"]
"docs_src/path_operation_advanced_configuration/tutorial007.py" = ["B904"]
"docs_src/custom_request_and_route/tutorial002.py" = ["B904"]
+"docs_src/dependencies/tutorial008_an.py" = ["F821"]
+"docs_src/dependencies/tutorial008_an_py39.py" = ["F821"]
+"docs_src/query_params_str_validations/tutorial012_an.py" = ["B006"]
+"docs_src/query_params_str_validations/tutorial012_an_py39.py" = ["B006"]
+"docs_src/query_params_str_validations/tutorial013_an.py" = ["B006"]
+"docs_src/query_params_str_validations/tutorial013_an_py39.py" = ["B006"]
[tool.ruff.isort]
known-third-party = ["fastapi", "pydantic", "starlette"]
diff --git a/scripts/zip-docs.sh b/scripts/zip-docs.sh
index 69315f5dd..47c3b0977 100644
--- a/scripts/zip-docs.sh
+++ b/scripts/zip-docs.sh
@@ -1,4 +1,4 @@
-#! /usr/bin/env bash
+#!/usr/bin/env bash
set -x
set -e
diff --git a/tests/main.py b/tests/main.py
index fce665704..15760c039 100644
--- a/tests/main.py
+++ b/tests/main.py
@@ -49,12 +49,7 @@ def get_bool_id(item_id: bool):
@app.get("/path/param/{item_id}")
-def get_path_param_id(item_id: str = Path()):
- return item_id
-
-
-@app.get("/path/param-required/{item_id}")
-def get_path_param_required_id(item_id: str = Path()):
+def get_path_param_id(item_id: Optional[str] = Path()):
return item_id
diff --git a/tests/test_additional_properties.py b/tests/test_additional_properties.py
index 016c1f734..516a569e4 100644
--- a/tests/test_additional_properties.py
+++ b/tests/test_additional_properties.py
@@ -19,92 +19,91 @@ def foo(items: Items):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/foo": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+def test_additional_properties_post():
+ response = client.post("/foo", json={"items": {"foo": 1, "bar": 2}})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"foo": 1, "bar": 2}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/foo": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
+ "summary": "Foo",
+ "operationId": "foo_foo_post",
+ "requestBody": {
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
+ "schema": {"$ref": "#/components/schemas/Items"}
}
},
+ "required": True,
},
- },
- "summary": "Foo",
- "operationId": "foo_foo_post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Items"}
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Items": {
+ "title": "Items",
+ "required": ["items"],
+ "type": "object",
+ "properties": {
+ "items": {
+ "title": "Items",
+ "type": "object",
+ "additionalProperties": {"type": "integer"},
}
},
- "required": True,
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Items": {
- "title": "Items",
- "required": ["items"],
- "type": "object",
- "properties": {
- "items": {
- "title": "Items",
- "type": "object",
- "additionalProperties": {"type": "integer"},
- }
},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
},
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
},
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
},
- },
- }
- },
-}
-
-
-def test_additional_properties_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
-def test_additional_properties_post():
- response = client.post("/foo", json={"items": {"foo": 1, "bar": 2}})
- assert response.status_code == 200, response.text
- assert response.json() == {"foo": 1, "bar": 2}
+ }
+ },
+ }
diff --git a/tests/test_additional_response_extra.py b/tests/test_additional_response_extra.py
index 1df1891e0..d62638c8f 100644
--- a/tests/test_additional_response_extra.py
+++ b/tests/test_additional_response_extra.py
@@ -17,36 +17,33 @@ router.include_router(sub_router, prefix="/items")
app.include_router(router)
-
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Item",
- "operationId": "read_item_items__get",
- }
- }
- },
-}
-
client = TestClient(app)
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
def test_path_operation():
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.json() == {"id": "foo"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__get",
+ }
+ }
+ },
+ }
diff --git a/tests/test_additional_responses_custom_model_in_callback.py b/tests/test_additional_responses_custom_model_in_callback.py
index a1072cc56..5c08eaa6d 100644
--- a/tests/test_additional_responses_custom_model_in_callback.py
+++ b/tests/test_additional_responses_custom_model_in_callback.py
@@ -25,114 +25,116 @@ def main_route(callback_url: HttpUrl):
pass # pragma: no cover
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/": {
- "post": {
- "summary": "Main Route",
- "operationId": "main_route__post",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Callback Url",
- "maxLength": 2083,
- "minLength": 1,
- "type": "string",
- "format": "uri",
+client = TestClient(app)
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/": {
+ "post": {
+ "summary": "Main Route",
+ "operationId": "main_route__post",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Callback Url",
+ "maxLength": 2083,
+ "minLength": 1,
+ "type": "string",
+ "format": "uri",
+ },
+ "name": "callback_url",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
},
- "name": "callback_url",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "callbacks": {
- "callback_route": {
- "{$callback_url}/callback/": {
- "get": {
- "summary": "Callback Route",
- "operationId": "callback_route__callback_url__callback__get",
- "responses": {
- "400": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/CustomModel"
+ "callbacks": {
+ "callback_route": {
+ "{$callback_url}/callback/": {
+ "get": {
+ "summary": "Callback Route",
+ "operationId": "callback_route__callback_url__callback__get",
+ "responses": {
+ "400": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CustomModel"
+ }
}
- }
+ },
+ "description": "Bad Request",
+ },
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
},
- "description": "Bad Request",
- },
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
},
- },
+ }
}
}
- }
- },
+ },
+ }
}
- }
- },
- "components": {
- "schemas": {
- "CustomModel": {
- "title": "CustomModel",
- "required": ["a"],
- "type": "object",
- "properties": {"a": {"title": "A", "type": "integer"}},
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
+ },
+ "components": {
+ "schemas": {
+ "CustomModel": {
+ "title": "CustomModel",
+ "required": ["a"],
+ "type": "object",
+ "properties": {"a": {"title": "A", "type": "integer"}},
},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
},
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
},
- },
- }
- },
-}
-
-client = TestClient(app)
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_additional_responses_custom_validationerror.py b/tests/test_additional_responses_custom_validationerror.py
index 811fe6922..052602768 100644
--- a/tests/test_additional_responses_custom_validationerror.py
+++ b/tests/test_additional_responses_custom_validationerror.py
@@ -30,71 +30,70 @@ async def a(id):
pass # pragma: no cover
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/a/{id}": {
- "get": {
- "responses": {
- "422": {
- "description": "Error",
- "content": {
- "application/vnd.api+json": {
- "schema": {"$ref": "#/components/schemas/JsonApiError"}
- }
- },
- },
- "200": {
- "description": "Successful Response",
- "content": {"application/vnd.api+json": {"schema": {}}},
- },
- },
- "summary": "A",
- "operationId": "a_a__id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Id"},
- "name": "id",
- "in": "path",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "Error": {
- "title": "Error",
- "required": ["status", "title"],
- "type": "object",
- "properties": {
- "status": {"title": "Status", "type": "string"},
- "title": {"title": "Title", "type": "string"},
- },
- },
- "JsonApiError": {
- "title": "JsonApiError",
- "required": ["errors"],
- "type": "object",
- "properties": {
- "errors": {
- "title": "Errors",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Error"},
- }
- },
- },
- }
- },
-}
-
-
client = TestClient(app)
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/a/{id}": {
+ "get": {
+ "responses": {
+ "422": {
+ "description": "Error",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/JsonApiError"
+ }
+ }
+ },
+ },
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/vnd.api+json": {"schema": {}}},
+ },
+ },
+ "summary": "A",
+ "operationId": "a_a__id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Id"},
+ "name": "id",
+ "in": "path",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Error": {
+ "title": "Error",
+ "required": ["status", "title"],
+ "type": "object",
+ "properties": {
+ "status": {"title": "Status", "type": "string"},
+ "title": {"title": "Title", "type": "string"},
+ },
+ },
+ "JsonApiError": {
+ "title": "JsonApiError",
+ "required": ["errors"],
+ "type": "object",
+ "properties": {
+ "errors": {
+ "title": "Errors",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Error"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_additional_responses_default_validationerror.py b/tests/test_additional_responses_default_validationerror.py
index cabb536d7..58de46ff6 100644
--- a/tests/test_additional_responses_default_validationerror.py
+++ b/tests/test_additional_responses_default_validationerror.py
@@ -9,77 +9,76 @@ async def a(id):
pass # pragma: no cover
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/a/{id}": {
- "get": {
- "responses": {
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+client = TestClient(app)
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/a/{id}": {
+ "get": {
+ "responses": {
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
+ },
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
},
},
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- },
- "summary": "A",
- "operationId": "a_a__id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Id"},
- "name": "id",
- "in": "path",
- }
- ],
+ "summary": "A",
+ "operationId": "a_a__id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Id"},
+ "name": "id",
+ "in": "path",
+ }
+ ],
+ }
}
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
},
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
},
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
},
- },
- }
- },
-}
-
-
-client = TestClient(app)
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
+ }
+ },
+ }
diff --git a/tests/test_additional_responses_response_class.py b/tests/test_additional_responses_response_class.py
index aa549b163..6746760f0 100644
--- a/tests/test_additional_responses_response_class.py
+++ b/tests/test_additional_responses_response_class.py
@@ -35,83 +35,82 @@ async def b():
pass # pragma: no cover
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/a": {
- "get": {
- "responses": {
- "500": {
- "description": "Error",
- "content": {
- "application/vnd.api+json": {
- "schema": {"$ref": "#/components/schemas/JsonApiError"}
- }
+client = TestClient(app)
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/a": {
+ "get": {
+ "responses": {
+ "500": {
+ "description": "Error",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/JsonApiError"
+ }
+ }
+ },
+ },
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/vnd.api+json": {"schema": {}}},
},
},
- "200": {
- "description": "Successful Response",
- "content": {"application/vnd.api+json": {"schema": {}}},
+ "summary": "A",
+ "operationId": "a_a_get",
+ }
+ },
+ "/b": {
+ "get": {
+ "responses": {
+ "500": {
+ "description": "Error",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Error"}
+ }
+ },
+ },
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
},
- },
- "summary": "A",
- "operationId": "a_a_get",
- }
+ "summary": "B",
+ "operationId": "b_b_get",
+ }
+ },
},
- "/b": {
- "get": {
- "responses": {
- "500": {
- "description": "Error",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Error"}
- }
- },
+ "components": {
+ "schemas": {
+ "Error": {
+ "title": "Error",
+ "required": ["status", "title"],
+ "type": "object",
+ "properties": {
+ "status": {"title": "Status", "type": "string"},
+ "title": {"title": "Title", "type": "string"},
},
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ },
+ "JsonApiError": {
+ "title": "JsonApiError",
+ "required": ["errors"],
+ "type": "object",
+ "properties": {
+ "errors": {
+ "title": "Errors",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Error"},
+ }
},
},
- "summary": "B",
- "operationId": "b_b_get",
}
},
- },
- "components": {
- "schemas": {
- "Error": {
- "title": "Error",
- "required": ["status", "title"],
- "type": "object",
- "properties": {
- "status": {"title": "Status", "type": "string"},
- "title": {"title": "Title", "type": "string"},
- },
- },
- "JsonApiError": {
- "title": "JsonApiError",
- "required": ["errors"],
- "type": "object",
- "properties": {
- "errors": {
- "title": "Errors",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Error"},
- }
- },
- },
- }
- },
-}
-
-
-client = TestClient(app)
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
+ }
diff --git a/tests/test_additional_responses_router.py b/tests/test_additional_responses_router.py
index fe4956f8f..58d54b733 100644
--- a/tests/test_additional_responses_router.py
+++ b/tests/test_additional_responses_router.py
@@ -53,103 +53,10 @@ async def d():
app.include_router(router)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/a": {
- "get": {
- "responses": {
- "501": {"description": "Error 1"},
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- },
- "summary": "A",
- "operationId": "a_a_get",
- }
- },
- "/b": {
- "get": {
- "responses": {
- "502": {"description": "Error 2"},
- "4XX": {"description": "Error with range, upper"},
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- },
- "summary": "B",
- "operationId": "b_b_get",
- }
- },
- "/c": {
- "get": {
- "responses": {
- "400": {"description": "Error with str"},
- "5XX": {"description": "Error with range, lower"},
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "default": {"description": "A default response"},
- },
- "summary": "C",
- "operationId": "c_c_get",
- }
- },
- "/d": {
- "get": {
- "responses": {
- "400": {"description": "Error with str"},
- "5XX": {
- "description": "Server Error",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/ResponseModel"}
- }
- },
- },
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "default": {
- "description": "Default Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/ResponseModel"}
- }
- },
- },
- },
- "summary": "D",
- "operationId": "d_d_get",
- }
- },
- },
- "components": {
- "schemas": {
- "ResponseModel": {
- "title": "ResponseModel",
- "required": ["message"],
- "type": "object",
- "properties": {"message": {"title": "Message", "type": "string"}},
- }
- }
- },
-}
client = TestClient(app)
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
def test_a():
response = client.get("/a")
assert response.status_code == 200, response.text
@@ -172,3 +79,99 @@ def test_d():
response = client.get("/d")
assert response.status_code == 200, response.text
assert response.json() == "d"
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/a": {
+ "get": {
+ "responses": {
+ "501": {"description": "Error 1"},
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ },
+ "summary": "A",
+ "operationId": "a_a_get",
+ }
+ },
+ "/b": {
+ "get": {
+ "responses": {
+ "502": {"description": "Error 2"},
+ "4XX": {"description": "Error with range, upper"},
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ },
+ "summary": "B",
+ "operationId": "b_b_get",
+ }
+ },
+ "/c": {
+ "get": {
+ "responses": {
+ "400": {"description": "Error with str"},
+ "5XX": {"description": "Error with range, lower"},
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "default": {"description": "A default response"},
+ },
+ "summary": "C",
+ "operationId": "c_c_get",
+ }
+ },
+ "/d": {
+ "get": {
+ "responses": {
+ "400": {"description": "Error with str"},
+ "5XX": {
+ "description": "Server Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ResponseModel"
+ }
+ }
+ },
+ },
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "default": {
+ "description": "Default Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ResponseModel"
+ }
+ }
+ },
+ },
+ },
+ "summary": "D",
+ "operationId": "d_d_get",
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "ResponseModel": {
+ "title": "ResponseModel",
+ "required": ["message"],
+ "type": "object",
+ "properties": {"message": {"title": "Message", "type": "string"}},
+ }
+ }
+ },
+ }
diff --git a/tests/test_ambiguous_params.py b/tests/test_ambiguous_params.py
new file mode 100644
index 000000000..42bcc27a1
--- /dev/null
+++ b/tests/test_ambiguous_params.py
@@ -0,0 +1,66 @@
+import pytest
+from fastapi import Depends, FastAPI, Path
+from fastapi.param_functions import Query
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+def test_no_annotated_defaults():
+ with pytest.raises(
+ AssertionError, match="Path parameters cannot have a default value"
+ ):
+
+ @app.get("/items/{item_id}/")
+ async def get_item(item_id: Annotated[int, Path(default=1)]):
+ pass # pragma: nocover
+
+ with pytest.raises(
+ AssertionError,
+ match=(
+ "`Query` default value cannot be set in `Annotated` for 'item_id'. Set the"
+ " default value with `=` instead."
+ ),
+ ):
+
+ @app.get("/")
+ async def get(item_id: Annotated[int, Query(default=1)]):
+ pass # pragma: nocover
+
+
+def test_no_multiple_annotations():
+ async def dep():
+ pass # pragma: nocover
+
+ with pytest.raises(
+ AssertionError,
+ match="Cannot specify multiple `Annotated` FastAPI arguments for 'foo'",
+ ):
+
+ @app.get("/")
+ async def get(foo: Annotated[int, Query(min_length=1), Query()]):
+ pass # pragma: nocover
+
+ with pytest.raises(
+ AssertionError,
+ match=(
+ "Cannot specify `Depends` in `Annotated` and default value"
+ " together for 'foo'"
+ ),
+ ):
+
+ @app.get("/")
+ async def get2(foo: Annotated[int, Depends(dep)] = Depends(dep)):
+ pass # pragma: nocover
+
+ with pytest.raises(
+ AssertionError,
+ match=(
+ "Cannot specify a FastAPI annotation in `Annotated` and `Depends` as a"
+ " default value together for 'foo'"
+ ),
+ ):
+
+ @app.get("/")
+ async def get3(foo: Annotated[int, Query(min_length=1)] = Depends(dep)):
+ pass # pragma: nocover
diff --git a/tests/test_annotated.py b/tests/test_annotated.py
new file mode 100644
index 000000000..a4f42b038
--- /dev/null
+++ b/tests/test_annotated.py
@@ -0,0 +1,288 @@
+import pytest
+from fastapi import APIRouter, FastAPI, Query
+from fastapi.testclient import TestClient
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.get("/default")
+async def default(foo: Annotated[str, Query()] = "foo"):
+ return {"foo": foo}
+
+
+@app.get("/required")
+async def required(foo: Annotated[str, Query(min_length=1)]):
+ return {"foo": foo}
+
+
+@app.get("/multiple")
+async def multiple(foo: Annotated[str, object(), Query(min_length=1)]):
+ return {"foo": foo}
+
+
+@app.get("/unrelated")
+async def unrelated(foo: Annotated[str, object()]):
+ return {"foo": foo}
+
+
+client = TestClient(app)
+
+foo_is_missing = {
+ "detail": [
+ {
+ "loc": ["query", "foo"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ }
+ ]
+}
+foo_is_short = {
+ "detail": [
+ {
+ "ctx": {"limit_value": 1},
+ "loc": ["query", "foo"],
+ "msg": "ensure this value has at least 1 characters",
+ "type": "value_error.any_str.min_length",
+ }
+ ]
+}
+
+
+@pytest.mark.parametrize(
+ "path,expected_status,expected_response",
+ [
+ ("/default", 200, {"foo": "foo"}),
+ ("/default?foo=bar", 200, {"foo": "bar"}),
+ ("/required?foo=bar", 200, {"foo": "bar"}),
+ ("/required", 422, foo_is_missing),
+ ("/required?foo=", 422, foo_is_short),
+ ("/multiple?foo=bar", 200, {"foo": "bar"}),
+ ("/multiple", 422, foo_is_missing),
+ ("/multiple?foo=", 422, foo_is_short),
+ ("/unrelated?foo=bar", 200, {"foo": "bar"}),
+ ("/unrelated", 422, foo_is_missing),
+ ],
+)
+def test_get(path, expected_status, expected_response):
+ response = client.get(path)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+def test_multiple_path():
+ app = FastAPI()
+
+ @app.get("/test1")
+ @app.get("/test2")
+ async def test(var: Annotated[str, Query()] = "bar"):
+ return {"foo": var}
+
+ client = TestClient(app)
+ response = client.get("/test1")
+ assert response.status_code == 200
+ assert response.json() == {"foo": "bar"}
+
+ response = client.get("/test1", params={"var": "baz"})
+ assert response.status_code == 200
+ assert response.json() == {"foo": "baz"}
+
+ response = client.get("/test2")
+ assert response.status_code == 200
+ assert response.json() == {"foo": "bar"}
+
+ response = client.get("/test2", params={"var": "baz"})
+ assert response.status_code == 200
+ assert response.json() == {"foo": "baz"}
+
+
+def test_nested_router():
+ app = FastAPI()
+
+ router = APIRouter(prefix="/nested")
+
+ @router.get("/test")
+ async def test(var: Annotated[str, Query()] = "bar"):
+ return {"foo": var}
+
+ app.include_router(router)
+
+ client = TestClient(app)
+
+ response = client.get("/nested/test")
+ assert response.status_code == 200
+ assert response.json() == {"foo": "bar"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/default": {
+ "get": {
+ "summary": "Default",
+ "operationId": "default_default_get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Foo",
+ "type": "string",
+ "default": "foo",
+ },
+ "name": "foo",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/required": {
+ "get": {
+ "summary": "Required",
+ "operationId": "required_required_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Foo",
+ "minLength": 1,
+ "type": "string",
+ },
+ "name": "foo",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/multiple": {
+ "get": {
+ "summary": "Multiple",
+ "operationId": "multiple_multiple_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Foo",
+ "minLength": 1,
+ "type": "string",
+ },
+ "name": "foo",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/unrelated": {
+ "get": {
+ "summary": "Unrelated",
+ "operationId": "unrelated_unrelated_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Foo", "type": "string"},
+ "name": "foo",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_application.py b/tests/test_application.py
index b7d72f9ad..e5f2f4387 100644
--- a/tests/test_application.py
+++ b/tests/test_application.py
@@ -5,1200 +5,1179 @@ from .main import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/api_route": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Non Operation",
- "operationId": "non_operation_api_route_get",
- }
- },
- "/non_decorated_route": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Non Decorated Route",
- "operationId": "non_decorated_route_non_decorated_route_get",
- }
- },
- "/text": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Get Text",
- "operationId": "get_text_text_get",
- }
- },
- "/path/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+
+@pytest.mark.parametrize(
+ "path,expected_status,expected_response",
+ [
+ ("/api_route", 200, {"message": "Hello World"}),
+ ("/non_decorated_route", 200, {"message": "Hello World"}),
+ ("/nonexistent", 404, {"detail": "Not Found"}),
+ ],
+)
+def test_get_path(path, expected_status, expected_response):
+ response = client.get(path)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+def test_swagger_ui():
+ response = client.get("/docs")
+ assert response.status_code == 200, response.text
+ assert response.headers["content-type"] == "text/html; charset=utf-8"
+ assert "swagger-ui-dist" in response.text
+ assert (
+ "oauth2RedirectUrl: window.location.origin + '/docs/oauth2-redirect'"
+ in response.text
+ )
+
+
+def test_swagger_ui_oauth2_redirect():
+ response = client.get("/docs/oauth2-redirect")
+ assert response.status_code == 200, response.text
+ assert response.headers["content-type"] == "text/html; charset=utf-8"
+ assert "window.opener.swaggerUIRedirectOauth2" in response.text
+
+
+def test_redoc():
+ response = client.get("/redoc")
+ assert response.status_code == 200, response.text
+ assert response.headers["content-type"] == "text/html; charset=utf-8"
+ assert "redoc@next" in response.text
+
+
+def test_enum_status_code_response():
+ response = client.get("/enum-status-code")
+ assert response.status_code == 201, response.text
+ assert response.json() == "foo bar"
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/api_route": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Non Operation",
+ "operationId": "non_operation_api_route_get",
+ }
+ },
+ "/non_decorated_route": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Non Decorated Route",
+ "operationId": "non_decorated_route_non_decorated_route_get",
+ }
+ },
+ "/text": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Get Text",
+ "operationId": "get_text_text_get",
+ }
+ },
+ "/path/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Id",
- "operationId": "get_id_path__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/str/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Id",
+ "operationId": "get_id_path__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/str/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Str Id",
- "operationId": "get_str_id_path_str__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/int/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Str Id",
+ "operationId": "get_str_id_path_str__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/int/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Int Id",
- "operationId": "get_int_id_path_int__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "integer"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/float/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Int Id",
+ "operationId": "get_int_id_path_int__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "integer"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/float/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Float Id",
- "operationId": "get_float_id_path_float__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "number"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/bool/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Float Id",
+ "operationId": "get_float_id_path_float__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "number"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/bool/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Bool Id",
- "operationId": "get_bool_id_path_bool__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "boolean"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Bool Id",
+ "operationId": "get_bool_id_path_bool__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "boolean"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Id",
- "operationId": "get_path_param_id_path_param__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-required/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Id",
+ "operationId": "get_path_param_id_path_param__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-minlength/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Required Id",
- "operationId": "get_path_param_required_id_path_param_required__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-minlength/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Min Length",
+ "operationId": "get_path_param_min_length_path_param_minlength__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "minLength": 3,
+ "type": "string",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-maxlength/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Min Length",
- "operationId": "get_path_param_min_length_path_param_minlength__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "minLength": 3,
- "type": "string",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-maxlength/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Max Length",
+ "operationId": "get_path_param_max_length_path_param_maxlength__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "maxLength": 3,
+ "type": "string",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-min_maxlength/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Max Length",
- "operationId": "get_path_param_max_length_path_param_maxlength__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "maxLength": 3,
- "type": "string",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-min_maxlength/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Min Max Length",
+ "operationId": "get_path_param_min_max_length_path_param_min_maxlength__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "maxLength": 3,
+ "minLength": 2,
+ "type": "string",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-gt/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Min Max Length",
- "operationId": "get_path_param_min_max_length_path_param_min_maxlength__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "maxLength": 3,
- "minLength": 2,
- "type": "string",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-gt/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Gt",
+ "operationId": "get_path_param_gt_path_param_gt__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "exclusiveMinimum": 3.0,
+ "type": "number",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-gt0/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Gt",
- "operationId": "get_path_param_gt_path_param_gt__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "exclusiveMinimum": 3.0,
- "type": "number",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-gt0/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Gt0",
+ "operationId": "get_path_param_gt0_path_param_gt0__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "exclusiveMinimum": 0.0,
+ "type": "number",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-ge/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Gt0",
- "operationId": "get_path_param_gt0_path_param_gt0__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "exclusiveMinimum": 0.0,
- "type": "number",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-ge/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Ge",
+ "operationId": "get_path_param_ge_path_param_ge__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "minimum": 3.0,
+ "type": "number",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-lt/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Ge",
- "operationId": "get_path_param_ge_path_param_ge__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "minimum": 3.0,
- "type": "number",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-lt/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Lt",
+ "operationId": "get_path_param_lt_path_param_lt__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "exclusiveMaximum": 3.0,
+ "type": "number",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-lt0/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Lt",
- "operationId": "get_path_param_lt_path_param_lt__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "exclusiveMaximum": 3.0,
- "type": "number",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-lt0/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Lt0",
+ "operationId": "get_path_param_lt0_path_param_lt0__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "exclusiveMaximum": 0.0,
+ "type": "number",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-le/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Lt0",
- "operationId": "get_path_param_lt0_path_param_lt0__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "exclusiveMaximum": 0.0,
- "type": "number",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-le/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Le",
+ "operationId": "get_path_param_le_path_param_le__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "maximum": 3.0,
+ "type": "number",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-lt-gt/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Le",
- "operationId": "get_path_param_le_path_param_le__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "maximum": 3.0,
- "type": "number",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-lt-gt/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Lt Gt",
+ "operationId": "get_path_param_lt_gt_path_param_lt_gt__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "exclusiveMaximum": 3.0,
+ "exclusiveMinimum": 1.0,
+ "type": "number",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-le-ge/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Lt Gt",
- "operationId": "get_path_param_lt_gt_path_param_lt_gt__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "exclusiveMaximum": 3.0,
- "exclusiveMinimum": 1.0,
- "type": "number",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-le-ge/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Le Ge",
+ "operationId": "get_path_param_le_ge_path_param_le_ge__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "maximum": 3.0,
+ "minimum": 1.0,
+ "type": "number",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-lt-int/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Le Ge",
- "operationId": "get_path_param_le_ge_path_param_le_ge__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "maximum": 3.0,
- "minimum": 1.0,
- "type": "number",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-lt-int/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Lt Int",
+ "operationId": "get_path_param_lt_int_path_param_lt_int__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "exclusiveMaximum": 3.0,
+ "type": "integer",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-gt-int/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Lt Int",
- "operationId": "get_path_param_lt_int_path_param_lt_int__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "exclusiveMaximum": 3.0,
- "type": "integer",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-gt-int/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Gt Int",
+ "operationId": "get_path_param_gt_int_path_param_gt_int__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "exclusiveMinimum": 3.0,
+ "type": "integer",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-le-int/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Gt Int",
- "operationId": "get_path_param_gt_int_path_param_gt_int__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "exclusiveMinimum": 3.0,
- "type": "integer",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-le-int/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Le Int",
+ "operationId": "get_path_param_le_int_path_param_le_int__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "maximum": 3.0,
+ "type": "integer",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-ge-int/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Le Int",
- "operationId": "get_path_param_le_int_path_param_le_int__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "maximum": 3.0,
- "type": "integer",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-ge-int/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Ge Int",
+ "operationId": "get_path_param_ge_int_path_param_ge_int__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "minimum": 3.0,
+ "type": "integer",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-lt-gt-int/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Ge Int",
- "operationId": "get_path_param_ge_int_path_param_ge_int__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "minimum": 3.0,
- "type": "integer",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-lt-gt-int/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Lt Gt Int",
+ "operationId": "get_path_param_lt_gt_int_path_param_lt_gt_int__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "exclusiveMaximum": 3.0,
+ "exclusiveMinimum": 1.0,
+ "type": "integer",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/path/param-le-ge-int/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Lt Gt Int",
- "operationId": "get_path_param_lt_gt_int_path_param_lt_gt_int__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "exclusiveMaximum": 3.0,
- "exclusiveMinimum": 1.0,
- "type": "integer",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/path/param-le-ge-int/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Path Param Le Ge Int",
+ "operationId": "get_path_param_le_ge_int_path_param_le_ge_int__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "maximum": 3.0,
+ "minimum": 1.0,
+ "type": "integer",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/query": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Path Param Le Ge Int",
- "operationId": "get_path_param_le_ge_int_path_param_le_ge_int__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "maximum": 3.0,
- "minimum": 1.0,
- "type": "integer",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/query": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Query",
+ "operationId": "get_query_query_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Query"},
+ "name": "query",
+ "in": "query",
+ }
+ ],
+ }
+ },
+ "/query/optional": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Query",
- "operationId": "get_query_query_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Query"},
- "name": "query",
- "in": "query",
- }
- ],
- }
- },
- "/query/optional": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Query Optional",
+ "operationId": "get_query_optional_query_optional_get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Query"},
+ "name": "query",
+ "in": "query",
+ }
+ ],
+ }
+ },
+ "/query/int": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Query Optional",
- "operationId": "get_query_optional_query_optional_get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Query"},
- "name": "query",
- "in": "query",
- }
- ],
- }
- },
- "/query/int": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Query Type",
+ "operationId": "get_query_type_query_int_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Query", "type": "integer"},
+ "name": "query",
+ "in": "query",
+ }
+ ],
+ }
+ },
+ "/query/int/optional": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Query Type",
- "operationId": "get_query_type_query_int_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Query", "type": "integer"},
- "name": "query",
- "in": "query",
- }
- ],
- }
- },
- "/query/int/optional": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Query Type Optional",
+ "operationId": "get_query_type_optional_query_int_optional_get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Query", "type": "integer"},
+ "name": "query",
+ "in": "query",
+ }
+ ],
+ }
+ },
+ "/query/int/default": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Query Type Optional",
- "operationId": "get_query_type_optional_query_int_optional_get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Query", "type": "integer"},
- "name": "query",
- "in": "query",
- }
- ],
- }
- },
- "/query/int/default": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Query Type Int Default",
+ "operationId": "get_query_type_int_default_query_int_default_get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Query",
+ "type": "integer",
+ "default": 10,
+ },
+ "name": "query",
+ "in": "query",
+ }
+ ],
+ }
+ },
+ "/query/param": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Query Type Int Default",
- "operationId": "get_query_type_int_default_query_int_default_get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Query", "type": "integer", "default": 10},
- "name": "query",
- "in": "query",
- }
- ],
- }
- },
- "/query/param": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Query Param",
+ "operationId": "get_query_param_query_param_get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Query"},
+ "name": "query",
+ "in": "query",
+ }
+ ],
+ }
+ },
+ "/query/param-required": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Query Param",
- "operationId": "get_query_param_query_param_get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Query"},
- "name": "query",
- "in": "query",
- }
- ],
- }
- },
- "/query/param-required": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Query Param Required",
+ "operationId": "get_query_param_required_query_param_required_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Query"},
+ "name": "query",
+ "in": "query",
+ }
+ ],
+ }
+ },
+ "/query/param-required/int": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Query Param Required",
- "operationId": "get_query_param_required_query_param_required_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Query"},
- "name": "query",
- "in": "query",
- }
- ],
- }
- },
- "/query/param-required/int": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ "summary": "Get Query Param Required Type",
+ "operationId": "get_query_param_required_type_query_param_required_int_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Query", "type": "integer"},
+ "name": "query",
+ "in": "query",
+ }
+ ],
+ }
+ },
+ "/enum-status-code": {
+ "get": {
+ "responses": {
+ "201": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "summary": "Get Enum Status Code",
+ "operationId": "get_enum_status_code_enum_status_code_get",
+ }
+ },
+ "/query/frozenset": {
+ "get": {
+ "summary": "Get Query Type Frozenset",
+ "operationId": "get_query_type_frozenset_query_frozenset_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Query",
+ "uniqueItems": True,
+ "type": "array",
+ "items": {"type": "integer"},
+ },
+ "name": "query",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- "summary": "Get Query Param Required Type",
- "operationId": "get_query_param_required_type_query_param_required_int_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Query", "type": "integer"},
- "name": "query",
- "in": "query",
- }
- ],
- }
+ }
+ },
},
- "/enum-status-code": {
- "get": {
- "responses": {
- "201": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
},
},
- "summary": "Get Enum Status Code",
- "operationId": "get_enum_status_code_enum_status_code_get",
- }
- },
- "/query/frozenset": {
- "get": {
- "summary": "Get Query Type Frozenset",
- "operationId": "get_query_type_frozenset_query_frozenset_get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Query",
- "uniqueItems": True,
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
"type": "array",
- "items": {"type": "integer"},
- },
- "name": "query",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
},
},
}
},
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-@pytest.mark.parametrize(
- "path,expected_status,expected_response",
- [
- ("/api_route", 200, {"message": "Hello World"}),
- ("/non_decorated_route", 200, {"message": "Hello World"}),
- ("/nonexistent", 404, {"detail": "Not Found"}),
- ("/openapi.json", 200, openapi_schema),
- ],
-)
-def test_get_path(path, expected_status, expected_response):
- response = client.get(path)
- assert response.status_code == expected_status
- assert response.json() == expected_response
-
-
-def test_swagger_ui():
- response = client.get("/docs")
- assert response.status_code == 200, response.text
- assert response.headers["content-type"] == "text/html; charset=utf-8"
- assert "swagger-ui-dist" in response.text
- assert (
- "oauth2RedirectUrl: window.location.origin + '/docs/oauth2-redirect'"
- in response.text
- )
-
-
-def test_swagger_ui_oauth2_redirect():
- response = client.get("/docs/oauth2-redirect")
- assert response.status_code == 200, response.text
- assert response.headers["content-type"] == "text/html; charset=utf-8"
- assert "window.opener.swaggerUIRedirectOauth2" in response.text
-
-
-def test_redoc():
- response = client.get("/redoc")
- assert response.status_code == 200, response.text
- assert response.headers["content-type"] == "text/html; charset=utf-8"
- assert "redoc@next" in response.text
-
-
-def test_enum_status_code_response():
- response = client.get("/enum-status-code")
- assert response.status_code == 201, response.text
- assert response.json() == "foo bar"
+ }
diff --git a/tests/test_custom_route_class.py b/tests/test_custom_route_class.py
index 2e8d9c6de..d1b18ef1d 100644
--- a/tests/test_custom_route_class.py
+++ b/tests/test_custom_route_class.py
@@ -46,49 +46,6 @@ app.include_router(router=router_a, prefix="/a")
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/a/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Get A",
- "operationId": "get_a_a__get",
- }
- },
- "/a/b/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Get B",
- "operationId": "get_b_a_b__get",
- }
- },
- "/a/b/c/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Get C",
- "operationId": "get_c_a_b_c__get",
- }
- },
- },
-}
-
@pytest.mark.parametrize(
"path,expected_status,expected_response",
@@ -96,7 +53,6 @@ openapi_schema = {
("/a", 200, {"msg": "A"}),
("/a/b", 200, {"msg": "B"}),
("/a/b/c", 200, {"msg": "C"}),
- ("/openapi.json", 200, openapi_schema),
],
)
def test_get_path(path, expected_status, expected_response):
@@ -113,3 +69,50 @@ def test_route_classes():
assert getattr(routes["/a/"], "x_type") == "A" # noqa: B009
assert getattr(routes["/a/b/"], "x_type") == "B" # noqa: B009
assert getattr(routes["/a/b/c/"], "x_type") == "C" # noqa: B009
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/a/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Get A",
+ "operationId": "get_a_a__get",
+ }
+ },
+ "/a/b/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Get B",
+ "operationId": "get_b_a_b__get",
+ }
+ },
+ "/a/b/c/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Get C",
+ "operationId": "get_c_a_b_c__get",
+ }
+ },
+ },
+ }
diff --git a/tests/test_dependency_duplicates.py b/tests/test_dependency_duplicates.py
index 33899134e..285fdf1ab 100644
--- a/tests/test_dependency_duplicates.py
+++ b/tests/test_dependency_duplicates.py
@@ -44,156 +44,6 @@ async def no_duplicates_sub(
return [item, sub_items]
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/with-duplicates": {
- "post": {
- "summary": "With Duplicates",
- "operationId": "with_duplicates_with_duplicates_post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- "/no-duplicates": {
- "post": {
- "summary": "No Duplicates",
- "operationId": "no_duplicates_no_duplicates_post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Body_no_duplicates_no_duplicates_post"
- }
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- "/with-duplicates-sub": {
- "post": {
- "summary": "No Duplicates Sub",
- "operationId": "no_duplicates_sub_with_duplicates_sub_post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- },
- "components": {
- "schemas": {
- "Body_no_duplicates_no_duplicates_post": {
- "title": "Body_no_duplicates_no_duplicates_post",
- "required": ["item", "item2"],
- "type": "object",
- "properties": {
- "item": {"$ref": "#/components/schemas/Item"},
- "item2": {"$ref": "#/components/schemas/Item"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "Item": {
- "title": "Item",
- "required": ["data"],
- "type": "object",
- "properties": {"data": {"title": "Data", "type": "string"}},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
def test_no_duplicates_invalid():
response = client.post("/no-duplicates", json={"item": {"data": "myitem"}})
assert response.status_code == 422, response.text
@@ -230,3 +80,152 @@ def test_sub_duplicates():
{"data": "myitem"},
[{"data": "myitem"}, {"data": "myitem"}],
]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/with-duplicates": {
+ "post": {
+ "summary": "With Duplicates",
+ "operationId": "with_duplicates_with_duplicates_post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/no-duplicates": {
+ "post": {
+ "summary": "No Duplicates",
+ "operationId": "no_duplicates_no_duplicates_post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_no_duplicates_no_duplicates_post"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/with-duplicates-sub": {
+ "post": {
+ "summary": "No Duplicates Sub",
+ "operationId": "no_duplicates_sub_with_duplicates_sub_post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_no_duplicates_no_duplicates_post": {
+ "title": "Body_no_duplicates_no_duplicates_post",
+ "required": ["item", "item2"],
+ "type": "object",
+ "properties": {
+ "item": {"$ref": "#/components/schemas/Item"},
+ "item2": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "Item": {
+ "title": "Item",
+ "required": ["data"],
+ "type": "object",
+ "properties": {"data": {"title": "Data", "type": "string"}},
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_deprecated_openapi_prefix.py b/tests/test_deprecated_openapi_prefix.py
index a3355256f..688b9837f 100644
--- a/tests/test_deprecated_openapi_prefix.py
+++ b/tests/test_deprecated_openapi_prefix.py
@@ -11,34 +11,32 @@ def read_main(request: Request):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/app": {
- "get": {
- "summary": "Read Main",
- "operationId": "read_main_app_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- }
- }
- },
- "servers": [{"url": "/api/v1"}],
-}
-
-
-def test_openapi():
- response = client.get("/openapi.json")
- assert response.status_code == 200
- assert response.json() == openapi_schema
-
def test_main():
response = client.get("/app")
assert response.status_code == 200
assert response.json() == {"message": "Hello World", "root_path": "/api/v1"}
+
+
+def test_openapi():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/app": {
+ "get": {
+ "summary": "Read Main",
+ "operationId": "read_main_app_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ }
+ },
+ "servers": [{"url": "/api/v1"}],
+ }
diff --git a/tests/test_duplicate_models_openapi.py b/tests/test_duplicate_models_openapi.py
index f077dfea0..116b2006a 100644
--- a/tests/test_duplicate_models_openapi.py
+++ b/tests/test_duplicate_models_openapi.py
@@ -23,60 +23,57 @@ def f():
return {"c": {}, "d": {"a": {}}}
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/": {
- "get": {
- "summary": "F",
- "operationId": "f__get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Model3"}
- }
- },
- }
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Model": {"title": "Model", "type": "object", "properties": {}},
- "Model2": {
- "title": "Model2",
- "required": ["a"],
- "type": "object",
- "properties": {"a": {"$ref": "#/components/schemas/Model"}},
- },
- "Model3": {
- "title": "Model3",
- "required": ["c", "d"],
- "type": "object",
- "properties": {
- "c": {"$ref": "#/components/schemas/Model"},
- "d": {"$ref": "#/components/schemas/Model2"},
- },
- },
- }
- },
-}
-
-
client = TestClient(app)
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
def test_get_api_route():
response = client.get("/")
assert response.status_code == 200, response.text
assert response.json() == {"c": {}, "d": {"a": {}}}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/": {
+ "get": {
+ "summary": "F",
+ "operationId": "f__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Model3"}
+ }
+ },
+ }
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Model": {"title": "Model", "type": "object", "properties": {}},
+ "Model2": {
+ "title": "Model2",
+ "required": ["a"],
+ "type": "object",
+ "properties": {"a": {"$ref": "#/components/schemas/Model"}},
+ },
+ "Model3": {
+ "title": "Model3",
+ "required": ["c", "d"],
+ "type": "object",
+ "properties": {
+ "c": {"$ref": "#/components/schemas/Model"},
+ "d": {"$ref": "#/components/schemas/Model2"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_extra_routes.py b/tests/test_extra_routes.py
index e979628a5..c0db62c19 100644
--- a/tests/test_extra_routes.py
+++ b/tests/test_extra_routes.py
@@ -52,273 +52,6 @@ def trace_item(item_id: str):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Get Items",
- "operationId": "get_items_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- },
- "delete": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Delete Item",
- "operationId": "delete_item_items__item_id__delete",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
- },
- "options": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Options Item",
- "operationId": "options_item_items__item_id__options",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- },
- "head": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Head Item",
- "operationId": "head_item_items__item_id__head",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- },
- "patch": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Patch Item",
- "operationId": "patch_item_items__item_id__patch",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
- },
- "trace": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Trace Item",
- "operationId": "trace_item_items__item_id__trace",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- },
- },
- "/items-not-decorated/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Get Not Decorated",
- "operationId": "get_not_decorated_items_not_decorated__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get_api_route():
response = client.get("/items/foo")
@@ -360,3 +93,270 @@ def test_trace():
response = client.request("trace", "/items/foo")
assert response.status_code == 200, response.text
assert response.headers["content-type"] == "message/http"
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Get Items",
+ "operationId": "get_items_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ },
+ "delete": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Delete Item",
+ "operationId": "delete_item_items__item_id__delete",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ "required": True,
+ },
+ },
+ "options": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Options Item",
+ "operationId": "options_item_items__item_id__options",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ },
+ "head": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Head Item",
+ "operationId": "head_item_items__item_id__head",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ },
+ "patch": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Patch Item",
+ "operationId": "patch_item_items__item_id__patch",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ "required": True,
+ },
+ },
+ "trace": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Trace Item",
+ "operationId": "trace_item_items__item_id__trace",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ },
+ },
+ "/items-not-decorated/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Get Not Decorated",
+ "operationId": "get_not_decorated_items_not_decorated__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_filter_pydantic_sub_model.py b/tests/test_filter_pydantic_sub_model.py
index 8814356a1..15b15f862 100644
--- a/tests/test_filter_pydantic_sub_model.py
+++ b/tests/test_filter_pydantic_sub_model.py
@@ -40,99 +40,6 @@ async def get_model_a(name: str, model_c=Depends(get_model_c)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/model/{name}": {
- "get": {
- "summary": "Get Model A",
- "operationId": "get_model_a_model__name__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Name", "type": "string"},
- "name": "name",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/ModelA"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "ModelA": {
- "title": "ModelA",
- "required": ["name", "model_b"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "description": {"title": "Description", "type": "string"},
- "model_b": {"$ref": "#/components/schemas/ModelB"},
- },
- },
- "ModelB": {
- "title": "ModelB",
- "required": ["username"],
- "type": "object",
- "properties": {"username": {"title": "Username", "type": "string"}},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
def test_filter_sub_model():
response = client.get("/model/modelA")
assert response.status_code == 200, response.text
@@ -153,3 +60,95 @@ def test_validator_is_cloned():
"type": "value_error",
}
]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/model/{name}": {
+ "get": {
+ "summary": "Get Model A",
+ "operationId": "get_model_a_model__name__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Name", "type": "string"},
+ "name": "name",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/ModelA"}
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ModelA": {
+ "title": "ModelA",
+ "required": ["name", "model_b"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ "model_b": {"$ref": "#/components/schemas/ModelB"},
+ },
+ },
+ "ModelB": {
+ "title": "ModelB",
+ "required": ["username"],
+ "type": "object",
+ "properties": {"username": {"title": "Username", "type": "string"}},
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_get_request_body.py b/tests/test_get_request_body.py
index 52a052faa..541147fa8 100644
--- a/tests/test_get_request_body.py
+++ b/tests/test_get_request_body.py
@@ -19,90 +19,89 @@ async def create_item(product: Product):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/product": {
- "get": {
- "summary": "Create Item",
- "operationId": "create_item_product_get",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Product"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
+def test_get_with_body():
+ body = {"name": "Foo", "description": "Some description", "price": 5.5}
+ response = client.request("GET", "/product", json=body)
+ assert response.json() == body
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/product": {
+ "get": {
+ "summary": "Create Item",
+ "operationId": "create_item_product_get",
+ "requestBody": {
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
+ "schema": {"$ref": "#/components/schemas/Product"}
}
},
+ "required": True,
},
- },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
}
- }
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
},
- },
- "Product": {
- "title": "Product",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "description": {"title": "Description", "type": "string"},
- "price": {"title": "Price", "type": "number"},
+ "Product": {
+ "title": "Product",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ },
},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
},
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
},
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
-def test_get_with_body():
- body = {"name": "Foo", "description": "Some description", "price": 5.5}
- response = client.request("GET", "/product", json=body)
- assert response.json() == body
+ }
+ },
+ }
diff --git a/tests/test_include_router_defaults_overrides.py b/tests/test_include_router_defaults_overrides.py
index ccb6c7229..ced56c84d 100644
--- a/tests/test_include_router_defaults_overrides.py
+++ b/tests/test_include_router_defaults_overrides.py
@@ -343,16 +343,6 @@ app.include_router(router2_default)
client = TestClient(app)
-def test_openapi():
- client = TestClient(app)
- with warnings.catch_warnings(record=True) as w:
- warnings.simplefilter("always")
- response = client.get("/openapi.json")
- assert issubclass(w[-1].category, UserWarning)
- assert "Duplicate Operation ID" in str(w[-1].message)
- assert response.json() == openapi_schema
-
-
def test_level1_override():
response = client.get("/override1?level1=foo")
assert response.json() == "foo"
@@ -445,6179 +435,6863 @@ def test_paths_level5(override1, override2, override3, override4, override5):
assert not override5 or "x-level5" in response.headers
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/override1": {
- "get": {
- "tags": ["path1a", "path1b"],
- "summary": "Path1 Override",
- "operationId": "path1_override_override1_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- "name": "level1",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-1": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+def test_openapi():
+ client = TestClient(app)
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter("always")
+ response = client.get("/openapi.json")
+ assert issubclass(w[-1].category, UserWarning)
+ assert "Duplicate Operation ID" in str(w[-1].message)
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/override1": {
+ "get": {
+ "tags": ["path1a", "path1b"],
+ "summary": "Path1 Override",
+ "operationId": "path1_override_override1_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level1", "type": "string"},
+ "name": "level1",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-1": {"schema": {}}},
},
- },
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/default1": {
- "get": {
- "summary": "Path1 Default",
- "operationId": "path1_default_default1_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- "name": "level1",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-0": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
- "500": {"description": "Server error level 0"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/default1": {
+ "get": {
+ "summary": "Path1 Default",
+ "operationId": "path1_default_default1_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level1", "type": "string"},
+ "name": "level1",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-0": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
}
- }
- },
- }
- },
- "/level1/level2/override3": {
- "get": {
- "tags": [
- "level1a",
- "level1b",
- "level2a",
- "level2b",
- "path3a",
- "path3b",
- ],
- "summary": "Path3 Override Router2 Override",
- "operationId": "path3_override_router2_override_level1_level2_override3_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- "name": "level3",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-3": {"schema": {}}},
},
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "402": {"description": "Client error level 2"},
- "403": {"description": "Client error level 3"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ "/level1/level2/override3": {
+ "get": {
+ "tags": [
+ "level1a",
+ "level1b",
+ "level2a",
+ "level2b",
+ "path3a",
+ "path3b",
+ ],
+ "summary": "Path3 Override Router2 Override",
+ "operationId": "path3_override_router2_override_level1_level2_override3_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level3", "type": "string"},
+ "name": "level3",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-3": {"schema": {}}},
},
- },
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "502": {"description": "Server error level 2"},
- "503": {"description": "Server error level 3"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "402": {"description": "Client error level 2"},
+ "403": {"description": "Client error level 3"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "502": {"description": "Server error level 2"},
+ "503": {"description": "Server error level 3"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/level2/default3": {
- "get": {
- "tags": ["level1a", "level1b", "level2a", "level2b"],
- "summary": "Path3 Default Router2 Override",
- "operationId": "path3_default_router2_override_level1_level2_default3_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- "name": "level3",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-2": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "402": {"description": "Client error level 2"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "502": {"description": "Server error level 2"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/level2/default3": {
+ "get": {
+ "tags": ["level1a", "level1b", "level2a", "level2b"],
+ "summary": "Path3 Default Router2 Override",
+ "operationId": "path3_default_router2_override_level1_level2_default3_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level3", "type": "string"},
+ "name": "level3",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-2": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "402": {"description": "Client error level 2"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "502": {"description": "Server error level 2"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/level2/level3/level4/override5": {
- "get": {
- "tags": [
- "level1a",
- "level1b",
- "level2a",
- "level2b",
- "level3a",
- "level3b",
- "level4a",
- "level4b",
- "path5a",
- "path5b",
- ],
- "summary": "Path5 Override Router4 Override",
- "operationId": "path5_override_router4_override_level1_level2_level3_level4_override5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-5": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "402": {"description": "Client error level 2"},
- "403": {"description": "Client error level 3"},
- "404": {"description": "Client error level 4"},
- "405": {"description": "Client error level 5"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "502": {"description": "Server error level 2"},
- "503": {"description": "Server error level 3"},
- "504": {"description": "Server error level 4"},
- "505": {"description": "Server error level 5"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/level2/level3/level4/override5": {
+ "get": {
+ "tags": [
+ "level1a",
+ "level1b",
+ "level2a",
+ "level2b",
+ "level3a",
+ "level3b",
+ "level4a",
+ "level4b",
+ "path5a",
+ "path5b",
+ ],
+ "summary": "Path5 Override Router4 Override",
+ "operationId": "path5_override_router4_override_level1_level2_level3_level4_override5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-5": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "402": {"description": "Client error level 2"},
+ "403": {"description": "Client error level 3"},
+ "404": {"description": "Client error level 4"},
+ "405": {"description": "Client error level 5"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "502": {"description": "Server error level 2"},
+ "503": {"description": "Server error level 3"},
+ "504": {"description": "Server error level 4"},
+ "505": {"description": "Server error level 5"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback4": {
- "/": {
- "get": {
- "summary": "Callback4",
- "operationId": "callback4__get",
- "parameters": [
- {
- "name": "level4",
- "in": "query",
- "required": True,
- "schema": {"title": "Level4", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback4": {
+ "/": {
+ "get": {
+ "summary": "Callback4",
+ "operationId": "callback4__get",
+ "parameters": [
+ {
+ "name": "level4",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level4",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback5": {
- "/": {
- "get": {
- "summary": "Callback5",
- "operationId": "callback5__get",
- "parameters": [
- {
- "name": "level5",
- "in": "query",
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback5": {
+ "/": {
+ "get": {
+ "summary": "Callback5",
+ "operationId": "callback5__get",
+ "parameters": [
+ {
+ "name": "level5",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level5",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/level2/level3/level4/default5": {
- "get": {
- "tags": [
- "level1a",
- "level1b",
- "level2a",
- "level2b",
- "level3a",
- "level3b",
- "level4a",
- "level4b",
- ],
- "summary": "Path5 Default Router4 Override",
- "operationId": "path5_default_router4_override_level1_level2_level3_level4_default5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-4": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "402": {"description": "Client error level 2"},
- "403": {"description": "Client error level 3"},
- "404": {"description": "Client error level 4"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "502": {"description": "Server error level 2"},
- "503": {"description": "Server error level 3"},
- "504": {"description": "Server error level 4"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/level2/level3/level4/default5": {
+ "get": {
+ "tags": [
+ "level1a",
+ "level1b",
+ "level2a",
+ "level2b",
+ "level3a",
+ "level3b",
+ "level4a",
+ "level4b",
+ ],
+ "summary": "Path5 Default Router4 Override",
+ "operationId": "path5_default_router4_override_level1_level2_level3_level4_default5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-4": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "402": {"description": "Client error level 2"},
+ "403": {"description": "Client error level 3"},
+ "404": {"description": "Client error level 4"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "502": {"description": "Server error level 2"},
+ "503": {"description": "Server error level 3"},
+ "504": {"description": "Server error level 4"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback4": {
- "/": {
- "get": {
- "summary": "Callback4",
- "operationId": "callback4__get",
- "parameters": [
- {
- "name": "level4",
- "in": "query",
- "required": True,
- "schema": {"title": "Level4", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback4": {
+ "/": {
+ "get": {
+ "summary": "Callback4",
+ "operationId": "callback4__get",
+ "parameters": [
+ {
+ "name": "level4",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level4",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/level2/level3/override5": {
- "get": {
- "tags": [
- "level1a",
- "level1b",
- "level2a",
- "level2b",
- "level3a",
- "level3b",
- "path5a",
- "path5b",
- ],
- "summary": "Path5 Override Router4 Default",
- "operationId": "path5_override_router4_default_level1_level2_level3_override5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-5": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "402": {"description": "Client error level 2"},
- "403": {"description": "Client error level 3"},
- "405": {"description": "Client error level 5"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "502": {"description": "Server error level 2"},
- "503": {"description": "Server error level 3"},
- "505": {"description": "Server error level 5"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/level2/level3/override5": {
+ "get": {
+ "tags": [
+ "level1a",
+ "level1b",
+ "level2a",
+ "level2b",
+ "level3a",
+ "level3b",
+ "path5a",
+ "path5b",
+ ],
+ "summary": "Path5 Override Router4 Default",
+ "operationId": "path5_override_router4_default_level1_level2_level3_override5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-5": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "402": {"description": "Client error level 2"},
+ "403": {"description": "Client error level 3"},
+ "405": {"description": "Client error level 5"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "502": {"description": "Server error level 2"},
+ "503": {"description": "Server error level 3"},
+ "505": {"description": "Server error level 5"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback5": {
- "/": {
- "get": {
- "summary": "Callback5",
- "operationId": "callback5__get",
- "parameters": [
- {
- "name": "level5",
- "in": "query",
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback5": {
+ "/": {
+ "get": {
+ "summary": "Callback5",
+ "operationId": "callback5__get",
+ "parameters": [
+ {
+ "name": "level5",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level5",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/level2/level3/default5": {
- "get": {
- "tags": [
- "level1a",
- "level1b",
- "level2a",
- "level2b",
- "level3a",
- "level3b",
- ],
- "summary": "Path5 Default Router4 Default",
- "operationId": "path5_default_router4_default_level1_level2_level3_default5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-3": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "402": {"description": "Client error level 2"},
- "403": {"description": "Client error level 3"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "502": {"description": "Server error level 2"},
- "503": {"description": "Server error level 3"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/level2/level3/default5": {
+ "get": {
+ "tags": [
+ "level1a",
+ "level1b",
+ "level2a",
+ "level2b",
+ "level3a",
+ "level3b",
+ ],
+ "summary": "Path5 Default Router4 Default",
+ "operationId": "path5_default_router4_default_level1_level2_level3_default5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-3": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "402": {"description": "Client error level 2"},
+ "403": {"description": "Client error level 3"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "502": {"description": "Server error level 2"},
+ "503": {"description": "Server error level 3"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/level2/level4/override5": {
- "get": {
- "tags": [
- "level1a",
- "level1b",
- "level2a",
- "level2b",
- "level4a",
- "level4b",
- "path5a",
- "path5b",
- ],
- "summary": "Path5 Override Router4 Override",
- "operationId": "path5_override_router4_override_level1_level2_level4_override5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-5": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "402": {"description": "Client error level 2"},
- "404": {"description": "Client error level 4"},
- "405": {"description": "Client error level 5"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "502": {"description": "Server error level 2"},
- "504": {"description": "Server error level 4"},
- "505": {"description": "Server error level 5"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback4": {
- "/": {
- "get": {
- "summary": "Callback4",
- "operationId": "callback4__get",
- "parameters": [
- {
- "name": "level4",
- "in": "query",
- "required": True,
- "schema": {"title": "Level4", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback5": {
- "/": {
- "get": {
- "summary": "Callback5",
- "operationId": "callback5__get",
- "parameters": [
- {
- "name": "level5",
- "in": "query",
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/level2/level4/default5": {
- "get": {
- "tags": [
- "level1a",
- "level1b",
- "level2a",
- "level2b",
- "level4a",
- "level4b",
- ],
- "summary": "Path5 Default Router4 Override",
- "operationId": "path5_default_router4_override_level1_level2_level4_default5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-4": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "402": {"description": "Client error level 2"},
- "404": {"description": "Client error level 4"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "502": {"description": "Server error level 2"},
- "504": {"description": "Server error level 4"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback4": {
- "/": {
- "get": {
- "summary": "Callback4",
- "operationId": "callback4__get",
- "parameters": [
- {
- "name": "level4",
- "in": "query",
- "required": True,
- "schema": {"title": "Level4", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/level2/override5": {
- "get": {
- "tags": [
- "level1a",
- "level1b",
- "level2a",
- "level2b",
- "path5a",
- "path5b",
- ],
- "summary": "Path5 Override Router4 Default",
- "operationId": "path5_override_router4_default_level1_level2_override5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-5": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "402": {"description": "Client error level 2"},
- "405": {"description": "Client error level 5"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "502": {"description": "Server error level 2"},
- "505": {"description": "Server error level 5"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback5": {
- "/": {
- "get": {
- "summary": "Callback5",
- "operationId": "callback5__get",
- "parameters": [
- {
- "name": "level5",
- "in": "query",
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/level2/level4/override5": {
+ "get": {
+ "tags": [
+ "level1a",
+ "level1b",
+ "level2a",
+ "level2b",
+ "level4a",
+ "level4b",
+ "path5a",
+ "path5b",
+ ],
+ "summary": "Path5 Override Router4 Override",
+ "operationId": "path5_override_router4_override_level1_level2_level4_override5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-5": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "402": {"description": "Client error level 2"},
+ "404": {"description": "Client error level 4"},
+ "405": {"description": "Client error level 5"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/level2/default5": {
- "get": {
- "tags": ["level1a", "level1b", "level2a", "level2b"],
- "summary": "Path5 Default Router4 Default",
- "operationId": "path5_default_router4_default_level1_level2_default5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-2": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "402": {"description": "Client error level 2"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
- }
+ },
},
- },
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "502": {"description": "Server error level 2"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "502": {"description": "Server error level 2"},
+ "504": {"description": "Server error level 4"},
+ "505": {"description": "Server error level 5"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/override3": {
- "get": {
- "tags": ["level1a", "level1b", "path3a", "path3b"],
- "summary": "Path3 Override Router2 Default",
- "operationId": "path3_override_router2_default_level1_override3_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- "name": "level3",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-3": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "403": {"description": "Client error level 3"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "503": {"description": "Server error level 3"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/default3": {
- "get": {
- "tags": ["level1a", "level1b"],
- "summary": "Path3 Default Router2 Default",
- "operationId": "path3_default_router2_default_level1_default3_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- "name": "level3",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-1": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- },
- }
- },
- "/level1/level3/level4/override5": {
- "get": {
- "tags": [
- "level1a",
- "level1b",
- "level3a",
- "level3b",
- "level4a",
- "level4b",
- "path5a",
- "path5b",
- ],
- "summary": "Path5 Override Router4 Override",
- "operationId": "path5_override_router4_override_level1_level3_level4_override5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-5": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "403": {"description": "Client error level 3"},
- "404": {"description": "Client error level 4"},
- "405": {"description": "Client error level 5"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "503": {"description": "Server error level 3"},
- "504": {"description": "Server error level 4"},
- "505": {"description": "Server error level 5"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback4": {
- "/": {
- "get": {
- "summary": "Callback4",
- "operationId": "callback4__get",
- "parameters": [
- {
- "name": "level4",
- "in": "query",
- "required": True,
- "schema": {"title": "Level4", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback5": {
- "/": {
- "get": {
- "summary": "Callback5",
- "operationId": "callback5__get",
- "parameters": [
- {
- "name": "level5",
- "in": "query",
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "callback4": {
+ "/": {
+ "get": {
+ "summary": "Callback4",
+ "operationId": "callback4__get",
+ "parameters": [
+ {
+ "name": "level4",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level4",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/level3/level4/default5": {
- "get": {
- "tags": [
- "level1a",
- "level1b",
- "level3a",
- "level3b",
- "level4a",
- "level4b",
- ],
- "summary": "Path5 Default Router4 Override",
- "operationId": "path5_default_router4_override_level1_level3_level4_default5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-4": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "403": {"description": "Client error level 3"},
- "404": {"description": "Client error level 4"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "503": {"description": "Server error level 3"},
- "504": {"description": "Server error level 4"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "callback5": {
+ "/": {
+ "get": {
+ "summary": "Callback5",
+ "operationId": "callback5__get",
+ "parameters": [
+ {
+ "name": "level5",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level5",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback4": {
- "/": {
- "get": {
- "summary": "Callback4",
- "operationId": "callback4__get",
- "parameters": [
- {
- "name": "level4",
- "in": "query",
- "required": True,
- "schema": {"title": "Level4", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/level3/override5": {
- "get": {
- "tags": [
- "level1a",
- "level1b",
- "level3a",
- "level3b",
- "path5a",
- "path5b",
- ],
- "summary": "Path5 Override Router4 Default",
- "operationId": "path5_override_router4_default_level1_level3_override5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-5": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "403": {"description": "Client error level 3"},
- "405": {"description": "Client error level 5"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "503": {"description": "Server error level 3"},
- "505": {"description": "Server error level 5"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/level2/level4/default5": {
+ "get": {
+ "tags": [
+ "level1a",
+ "level1b",
+ "level2a",
+ "level2b",
+ "level4a",
+ "level4b",
+ ],
+ "summary": "Path5 Default Router4 Override",
+ "operationId": "path5_default_router4_override_level1_level2_level4_default5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-4": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "402": {"description": "Client error level 2"},
+ "404": {"description": "Client error level 4"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "502": {"description": "Server error level 2"},
+ "504": {"description": "Server error level 4"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback5": {
- "/": {
- "get": {
- "summary": "Callback5",
- "operationId": "callback5__get",
- "parameters": [
- {
- "name": "level5",
- "in": "query",
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/level3/default5": {
- "get": {
- "tags": ["level1a", "level1b", "level3a", "level3b"],
- "summary": "Path5 Default Router4 Default",
- "operationId": "path5_default_router4_default_level1_level3_default5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-3": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "403": {"description": "Client error level 3"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "503": {"description": "Server error level 3"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "callback4": {
+ "/": {
+ "get": {
+ "summary": "Callback4",
+ "operationId": "callback4__get",
+ "parameters": [
+ {
+ "name": "level4",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level4",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/level2/override5": {
+ "get": {
+ "tags": [
+ "level1a",
+ "level1b",
+ "level2a",
+ "level2b",
+ "path5a",
+ "path5b",
+ ],
+ "summary": "Path5 Override Router4 Default",
+ "operationId": "path5_override_router4_default_level1_level2_override5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-5": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "402": {"description": "Client error level 2"},
+ "405": {"description": "Client error level 5"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "502": {"description": "Server error level 2"},
+ "505": {"description": "Server error level 5"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- }
- },
- "/level1/level4/override5": {
- "get": {
- "tags": [
- "level1a",
- "level1b",
- "level4a",
- "level4b",
- "path5a",
- "path5b",
- ],
- "summary": "Path5 Override Router4 Override",
- "operationId": "path5_override_router4_override_level1_level4_override5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-5": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "404": {"description": "Client error level 4"},
- "405": {"description": "Client error level 5"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "504": {"description": "Server error level 4"},
- "505": {"description": "Server error level 5"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback5": {
+ "/": {
+ "get": {
+ "summary": "Callback5",
+ "operationId": "callback5__get",
+ "parameters": [
+ {
+ "name": "level5",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level5",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback4": {
- "/": {
- "get": {
- "summary": "Callback4",
- "operationId": "callback4__get",
- "parameters": [
- {
- "name": "level4",
- "in": "query",
- "required": True,
- "schema": {"title": "Level4", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/level2/default5": {
+ "get": {
+ "tags": ["level1a", "level1b", "level2a", "level2b"],
+ "summary": "Path5 Default Router4 Default",
+ "operationId": "path5_default_router4_default_level1_level2_default5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-2": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "402": {"description": "Client error level 2"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "502": {"description": "Server error level 2"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback5": {
- "/": {
- "get": {
- "summary": "Callback5",
- "operationId": "callback5__get",
- "parameters": [
- {
- "name": "level5",
- "in": "query",
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/level4/default5": {
- "get": {
- "tags": ["level1a", "level1b", "level4a", "level4b"],
- "summary": "Path5 Default Router4 Override",
- "operationId": "path5_default_router4_override_level1_level4_default5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-4": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "404": {"description": "Client error level 4"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "504": {"description": "Server error level 4"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/override3": {
+ "get": {
+ "tags": ["level1a", "level1b", "path3a", "path3b"],
+ "summary": "Path3 Override Router2 Default",
+ "operationId": "path3_override_router2_default_level1_override3_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level3", "type": "string"},
+ "name": "level3",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-3": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "403": {"description": "Client error level 3"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "503": {"description": "Server error level 3"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback4": {
- "/": {
- "get": {
- "summary": "Callback4",
- "operationId": "callback4__get",
- "parameters": [
- {
- "name": "level4",
- "in": "query",
- "required": True,
- "schema": {"title": "Level4", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/override5": {
- "get": {
- "tags": ["level1a", "level1b", "path5a", "path5b"],
- "summary": "Path5 Override Router4 Default",
- "operationId": "path5_override_router4_default_level1_override5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-5": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "405": {"description": "Client error level 5"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- "505": {"description": "Server error level 5"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/default3": {
+ "get": {
+ "tags": ["level1a", "level1b"],
+ "summary": "Path3 Default Router2 Default",
+ "operationId": "path3_default_router2_default_level1_default3_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level3", "type": "string"},
+ "name": "level3",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-1": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback5": {
- "/": {
- "get": {
- "summary": "Callback5",
- "operationId": "callback5__get",
- "parameters": [
- {
- "name": "level5",
- "in": "query",
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level1/default5": {
- "get": {
- "tags": ["level1a", "level1b"],
- "summary": "Path5 Default Router4 Default",
- "operationId": "path5_default_router4_default_level1_default5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-1": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "401": {"description": "Client error level 1"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
- "500": {"description": "Server error level 0"},
- "501": {"description": "Server error level 1"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ }
+ },
+ "/level1/level3/level4/override5": {
+ "get": {
+ "tags": [
+ "level1a",
+ "level1b",
+ "level3a",
+ "level3b",
+ "level4a",
+ "level4b",
+ "path5a",
+ "path5b",
+ ],
+ "summary": "Path5 Override Router4 Override",
+ "operationId": "path5_override_router4_override_level1_level3_level4_override5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-5": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "403": {"description": "Client error level 3"},
+ "404": {"description": "Client error level 4"},
+ "405": {"description": "Client error level 5"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "503": {"description": "Server error level 3"},
+ "504": {"description": "Server error level 4"},
+ "505": {"description": "Server error level 5"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback1": {
- "/": {
- "get": {
- "summary": "Callback1",
- "operationId": "callback1__get",
- "parameters": [
- {
- "name": "level1",
- "in": "query",
- "required": True,
- "schema": {"title": "Level1", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- }
- },
- "/level2/override3": {
- "get": {
- "tags": ["level2a", "level2b", "path3a", "path3b"],
- "summary": "Path3 Override Router2 Override",
- "operationId": "path3_override_router2_override_level2_override3_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- "name": "level3",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-3": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "402": {"description": "Client error level 2"},
- "403": {"description": "Client error level 3"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "502": {"description": "Server error level 2"},
- "503": {"description": "Server error level 3"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ },
+ "callback4": {
+ "/": {
+ "get": {
+ "summary": "Callback4",
+ "operationId": "callback4__get",
+ "parameters": [
+ {
+ "name": "level4",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level4",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ }
+ },
+ "callback5": {
+ "/": {
+ "get": {
+ "summary": "Callback5",
+ "operationId": "callback5__get",
+ "parameters": [
+ {
+ "name": "level5",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level5",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/level3/level4/default5": {
+ "get": {
+ "tags": [
+ "level1a",
+ "level1b",
+ "level3a",
+ "level3b",
+ "level4a",
+ "level4b",
+ ],
+ "summary": "Path5 Default Router4 Override",
+ "operationId": "path5_default_router4_override_level1_level3_level4_default5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-4": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "403": {"description": "Client error level 3"},
+ "404": {"description": "Client error level 4"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "503": {"description": "Server error level 3"},
+ "504": {"description": "Server error level 4"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level2/default3": {
- "get": {
- "tags": ["level2a", "level2b"],
- "summary": "Path3 Default Router2 Override",
- "operationId": "path3_default_router2_override_level2_default3_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- "name": "level3",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-2": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "402": {"description": "Client error level 2"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "502": {"description": "Server error level 2"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ }
+ },
+ "callback4": {
+ "/": {
+ "get": {
+ "summary": "Callback4",
+ "operationId": "callback4__get",
+ "parameters": [
+ {
+ "name": "level4",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level4",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/level3/override5": {
+ "get": {
+ "tags": [
+ "level1a",
+ "level1b",
+ "level3a",
+ "level3b",
+ "path5a",
+ "path5b",
+ ],
+ "summary": "Path5 Override Router4 Default",
+ "operationId": "path5_override_router4_default_level1_level3_override5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-5": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "403": {"description": "Client error level 3"},
+ "405": {"description": "Client error level 5"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "503": {"description": "Server error level 3"},
+ "505": {"description": "Server error level 5"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level2/level3/level4/override5": {
- "get": {
- "tags": [
- "level2a",
- "level2b",
- "level3a",
- "level3b",
- "level4a",
- "level4b",
- "path5a",
- "path5b",
- ],
- "summary": "Path5 Override Router4 Override",
- "operationId": "path5_override_router4_override_level2_level3_level4_override5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-5": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "402": {"description": "Client error level 2"},
- "403": {"description": "Client error level 3"},
- "404": {"description": "Client error level 4"},
- "405": {"description": "Client error level 5"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "502": {"description": "Server error level 2"},
- "503": {"description": "Server error level 3"},
- "504": {"description": "Server error level 4"},
- "505": {"description": "Server error level 5"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ }
+ },
+ "callback5": {
+ "/": {
+ "get": {
+ "summary": "Callback5",
+ "operationId": "callback5__get",
+ "parameters": [
+ {
+ "name": "level5",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level5",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/level3/default5": {
+ "get": {
+ "tags": ["level1a", "level1b", "level3a", "level3b"],
+ "summary": "Path5 Default Router4 Default",
+ "operationId": "path5_default_router4_default_level1_level3_default5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-3": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "403": {"description": "Client error level 3"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "503": {"description": "Server error level 3"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ }
+ },
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback4": {
- "/": {
- "get": {
- "summary": "Callback4",
- "operationId": "callback4__get",
- "parameters": [
- {
- "name": "level4",
- "in": "query",
- "required": True,
- "schema": {"title": "Level4", "type": "string"},
+ }
+ },
+ "/level1/level4/override5": {
+ "get": {
+ "tags": [
+ "level1a",
+ "level1b",
+ "level4a",
+ "level4b",
+ "path5a",
+ "path5b",
+ ],
+ "summary": "Path5 Override Router4 Override",
+ "operationId": "path5_override_router4_override_level1_level4_override5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-5": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "404": {"description": "Client error level 4"},
+ "405": {"description": "Client error level 5"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "504": {"description": "Server error level 4"},
+ "505": {"description": "Server error level 5"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback5": {
- "/": {
- "get": {
- "summary": "Callback5",
- "operationId": "callback5__get",
- "parameters": [
- {
- "name": "level5",
- "in": "query",
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ }
+ },
+ "callback4": {
+ "/": {
+ "get": {
+ "summary": "Callback4",
+ "operationId": "callback4__get",
+ "parameters": [
+ {
+ "name": "level4",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level4",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level2/level3/level4/default5": {
- "get": {
- "tags": [
- "level2a",
- "level2b",
- "level3a",
- "level3b",
- "level4a",
- "level4b",
- ],
- "summary": "Path5 Default Router4 Override",
- "operationId": "path5_default_router4_override_level2_level3_level4_default5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-4": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "402": {"description": "Client error level 2"},
- "403": {"description": "Client error level 3"},
- "404": {"description": "Client error level 4"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ },
+ "callback5": {
+ "/": {
+ "get": {
+ "summary": "Callback5",
+ "operationId": "callback5__get",
+ "parameters": [
+ {
+ "name": "level5",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level5",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
}
}
},
},
- "500": {"description": "Server error level 0"},
- "502": {"description": "Server error level 2"},
- "503": {"description": "Server error level 3"},
- "504": {"description": "Server error level 4"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/level4/default5": {
+ "get": {
+ "tags": ["level1a", "level1b", "level4a", "level4b"],
+ "summary": "Path5 Default Router4 Override",
+ "operationId": "path5_default_router4_override_level1_level4_default5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-4": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "404": {"description": "Client error level 4"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "504": {"description": "Server error level 4"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback4": {
+ "/": {
+ "get": {
+ "summary": "Callback4",
+ "operationId": "callback4__get",
+ "parameters": [
+ {
+ "name": "level4",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level4",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback4": {
- "/": {
- "get": {
- "summary": "Callback4",
- "operationId": "callback4__get",
- "parameters": [
- {
- "name": "level4",
- "in": "query",
- "required": True,
- "schema": {"title": "Level4", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/override5": {
+ "get": {
+ "tags": ["level1a", "level1b", "path5a", "path5b"],
+ "summary": "Path5 Override Router4 Default",
+ "operationId": "path5_override_router4_default_level1_override5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-5": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "405": {"description": "Client error level 5"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ "505": {"description": "Server error level 5"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level2/level3/override5": {
- "get": {
- "tags": [
- "level2a",
- "level2b",
- "level3a",
- "level3b",
- "path5a",
- "path5b",
- ],
- "summary": "Path5 Override Router4 Default",
- "operationId": "path5_override_router4_default_level2_level3_override5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-5": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "402": {"description": "Client error level 2"},
- "403": {"description": "Client error level 3"},
- "405": {"description": "Client error level 5"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "502": {"description": "Server error level 2"},
- "503": {"description": "Server error level 3"},
- "505": {"description": "Server error level 5"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback5": {
+ "/": {
+ "get": {
+ "summary": "Callback5",
+ "operationId": "callback5__get",
+ "parameters": [
+ {
+ "name": "level5",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level5",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level1/default5": {
+ "get": {
+ "tags": ["level1a", "level1b"],
+ "summary": "Path5 Default Router4 Default",
+ "operationId": "path5_default_router4_default_level1_default5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-1": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "401": {"description": "Client error level 1"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "501": {"description": "Server error level 1"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback5": {
- "/": {
- "get": {
- "summary": "Callback5",
- "operationId": "callback5__get",
- "parameters": [
- {
- "name": "level5",
- "in": "query",
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback1": {
+ "/": {
+ "get": {
+ "summary": "Callback1",
+ "operationId": "callback1__get",
+ "parameters": [
+ {
+ "name": "level1",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level1",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level2/level3/default5": {
- "get": {
- "tags": ["level2a", "level2b", "level3a", "level3b"],
- "summary": "Path5 Default Router4 Default",
- "operationId": "path5_default_router4_default_level2_level3_default5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-3": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "402": {"description": "Client error level 2"},
- "403": {"description": "Client error level 3"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
- "500": {"description": "Server error level 0"},
- "502": {"description": "Server error level 2"},
- "503": {"description": "Server error level 3"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ }
+ },
+ "/level2/override3": {
+ "get": {
+ "tags": ["level2a", "level2b", "path3a", "path3b"],
+ "summary": "Path3 Override Router2 Override",
+ "operationId": "path3_override_router2_override_level2_override3_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level3", "type": "string"},
+ "name": "level3",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-3": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "402": {"description": "Client error level 2"},
+ "403": {"description": "Client error level 3"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "502": {"description": "Server error level 2"},
+ "503": {"description": "Server error level 3"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level2/level4/override5": {
- "get": {
- "tags": [
- "level2a",
- "level2b",
- "level4a",
- "level4b",
- "path5a",
- "path5b",
- ],
- "summary": "Path5 Override Router4 Override",
- "operationId": "path5_override_router4_override_level2_level4_override5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-5": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "402": {"description": "Client error level 2"},
- "404": {"description": "Client error level 4"},
- "405": {"description": "Client error level 5"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
- "500": {"description": "Server error level 0"},
- "502": {"description": "Server error level 2"},
- "504": {"description": "Server error level 4"},
- "505": {"description": "Server error level 5"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level2/default3": {
+ "get": {
+ "tags": ["level2a", "level2b"],
+ "summary": "Path3 Default Router2 Override",
+ "operationId": "path3_default_router2_override_level2_default3_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level3", "type": "string"},
+ "name": "level3",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-2": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "402": {"description": "Client error level 2"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "502": {"description": "Server error level 2"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback4": {
- "/": {
- "get": {
- "summary": "Callback4",
- "operationId": "callback4__get",
- "parameters": [
- {
- "name": "level4",
- "in": "query",
- "required": True,
- "schema": {"title": "Level4", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level2/level3/level4/override5": {
+ "get": {
+ "tags": [
+ "level2a",
+ "level2b",
+ "level3a",
+ "level3b",
+ "level4a",
+ "level4b",
+ "path5a",
+ "path5b",
+ ],
+ "summary": "Path5 Override Router4 Override",
+ "operationId": "path5_override_router4_override_level2_level3_level4_override5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-5": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "402": {"description": "Client error level 2"},
+ "403": {"description": "Client error level 3"},
+ "404": {"description": "Client error level 4"},
+ "405": {"description": "Client error level 5"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "502": {"description": "Server error level 2"},
+ "503": {"description": "Server error level 3"},
+ "504": {"description": "Server error level 4"},
+ "505": {"description": "Server error level 5"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback5": {
- "/": {
- "get": {
- "summary": "Callback5",
- "operationId": "callback5__get",
- "parameters": [
- {
- "name": "level5",
- "in": "query",
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level2/level4/default5": {
- "get": {
- "tags": ["level2a", "level2b", "level4a", "level4b"],
- "summary": "Path5 Default Router4 Override",
- "operationId": "path5_default_router4_override_level2_level4_default5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-4": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "402": {"description": "Client error level 2"},
- "404": {"description": "Client error level 4"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "502": {"description": "Server error level 2"},
- "504": {"description": "Server error level 4"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback4": {
+ "/": {
+ "get": {
+ "summary": "Callback4",
+ "operationId": "callback4__get",
+ "parameters": [
+ {
+ "name": "level4",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level4",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback4": {
- "/": {
- "get": {
- "summary": "Callback4",
- "operationId": "callback4__get",
- "parameters": [
- {
- "name": "level4",
- "in": "query",
- "required": True,
- "schema": {"title": "Level4", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback5": {
+ "/": {
+ "get": {
+ "summary": "Callback5",
+ "operationId": "callback5__get",
+ "parameters": [
+ {
+ "name": "level5",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level5",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level2/override5": {
- "get": {
- "tags": ["level2a", "level2b", "path5a", "path5b"],
- "summary": "Path5 Override Router4 Default",
- "operationId": "path5_override_router4_default_level2_override5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-5": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "402": {"description": "Client error level 2"},
- "405": {"description": "Client error level 5"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
- "500": {"description": "Server error level 0"},
- "502": {"description": "Server error level 2"},
- "505": {"description": "Server error level 5"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level2/level3/level4/default5": {
+ "get": {
+ "tags": [
+ "level2a",
+ "level2b",
+ "level3a",
+ "level3b",
+ "level4a",
+ "level4b",
+ ],
+ "summary": "Path5 Default Router4 Override",
+ "operationId": "path5_default_router4_override_level2_level3_level4_default5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-4": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "402": {"description": "Client error level 2"},
+ "403": {"description": "Client error level 3"},
+ "404": {"description": "Client error level 4"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "502": {"description": "Server error level 2"},
+ "503": {"description": "Server error level 3"},
+ "504": {"description": "Server error level 4"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ }
+ },
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ },
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ }
+ },
+ "callback4": {
+ "/": {
+ "get": {
+ "summary": "Callback4",
+ "operationId": "callback4__get",
+ "parameters": [
+ {
+ "name": "level4",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level4",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback5": {
- "/": {
- "get": {
- "summary": "Callback5",
- "operationId": "callback5__get",
- "parameters": [
- {
- "name": "level5",
- "in": "query",
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level2/level3/override5": {
+ "get": {
+ "tags": [
+ "level2a",
+ "level2b",
+ "level3a",
+ "level3b",
+ "path5a",
+ "path5b",
+ ],
+ "summary": "Path5 Override Router4 Default",
+ "operationId": "path5_override_router4_default_level2_level3_override5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-5": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "402": {"description": "Client error level 2"},
+ "403": {"description": "Client error level 3"},
+ "405": {"description": "Client error level 5"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "502": {"description": "Server error level 2"},
+ "503": {"description": "Server error level 3"},
+ "505": {"description": "Server error level 5"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level2/default5": {
- "get": {
- "tags": ["level2a", "level2b"],
- "summary": "Path5 Default Router4 Default",
- "operationId": "path5_default_router4_default_level2_default5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-2": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "402": {"description": "Client error level 2"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ },
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "502": {"description": "Server error level 2"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ }
+ },
+ "callback5": {
+ "/": {
+ "get": {
+ "summary": "Callback5",
+ "operationId": "callback5__get",
+ "parameters": [
+ {
+ "name": "level5",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level5",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback2": {
- "/": {
- "get": {
- "summary": "Callback2",
- "operationId": "callback2__get",
- "parameters": [
- {
- "name": "level2",
- "in": "query",
- "required": True,
- "schema": {"title": "Level2", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level2/level3/default5": {
+ "get": {
+ "tags": ["level2a", "level2b", "level3a", "level3b"],
+ "summary": "Path5 Default Router4 Default",
+ "operationId": "path5_default_router4_default_level2_level3_default5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-3": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "402": {"description": "Client error level 2"},
+ "403": {"description": "Client error level 3"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "502": {"description": "Server error level 2"},
+ "503": {"description": "Server error level 3"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/override3": {
- "get": {
- "tags": ["path3a", "path3b"],
- "summary": "Path3 Override Router2 Default",
- "operationId": "path3_override_router2_default_override3_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- "name": "level3",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-3": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "403": {"description": "Client error level 3"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "503": {"description": "Server error level 3"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ }
+ },
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level2/level4/override5": {
+ "get": {
+ "tags": [
+ "level2a",
+ "level2b",
+ "level4a",
+ "level4b",
+ "path5a",
+ "path5b",
+ ],
+ "summary": "Path5 Override Router4 Override",
+ "operationId": "path5_override_router4_override_level2_level4_override5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-5": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "402": {"description": "Client error level 2"},
+ "404": {"description": "Client error level 4"},
+ "405": {"description": "Client error level 5"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "502": {"description": "Server error level 2"},
+ "504": {"description": "Server error level 4"},
+ "505": {"description": "Server error level 5"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ }
+ },
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- },
- "deprecated": True,
- }
- },
- "/default3": {
- "get": {
- "summary": "Path3 Default Router2 Default",
- "operationId": "path3_default_router2_default_default3_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- "name": "level3",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-0": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ },
+ "callback4": {
+ "/": {
+ "get": {
+ "summary": "Callback4",
+ "operationId": "callback4__get",
+ "parameters": [
+ {
+ "name": "level4",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level4",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
}
}
},
- },
- "500": {"description": "Server error level 0"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "callback5": {
+ "/": {
+ "get": {
+ "summary": "Callback5",
+ "operationId": "callback5__get",
+ "parameters": [
+ {
+ "name": "level5",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level5",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- }
- },
- }
- },
- "/level3/level4/override5": {
- "get": {
- "tags": [
- "level3a",
- "level3b",
- "level4a",
- "level4b",
- "path5a",
- "path5b",
- ],
- "summary": "Path5 Override Router4 Override",
- "operationId": "path5_override_router4_override_level3_level4_override5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-5": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "403": {"description": "Client error level 3"},
- "404": {"description": "Client error level 4"},
- "405": {"description": "Client error level 5"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
- "500": {"description": "Server error level 0"},
- "503": {"description": "Server error level 3"},
- "504": {"description": "Server error level 4"},
- "505": {"description": "Server error level 5"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level2/level4/default5": {
+ "get": {
+ "tags": ["level2a", "level2b", "level4a", "level4b"],
+ "summary": "Path5 Default Router4 Override",
+ "operationId": "path5_default_router4_override_level2_level4_default5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-4": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "402": {"description": "Client error level 2"},
+ "404": {"description": "Client error level 4"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "502": {"description": "Server error level 2"},
+ "504": {"description": "Server error level 4"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback4": {
- "/": {
- "get": {
- "summary": "Callback4",
- "operationId": "callback4__get",
- "parameters": [
- {
- "name": "level4",
- "in": "query",
- "required": True,
- "schema": {"title": "Level4", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback4": {
+ "/": {
+ "get": {
+ "summary": "Callback4",
+ "operationId": "callback4__get",
+ "parameters": [
+ {
+ "name": "level4",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level4",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback5": {
- "/": {
- "get": {
- "summary": "Callback5",
- "operationId": "callback5__get",
- "parameters": [
- {
- "name": "level5",
- "in": "query",
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level2/override5": {
+ "get": {
+ "tags": ["level2a", "level2b", "path5a", "path5b"],
+ "summary": "Path5 Override Router4 Default",
+ "operationId": "path5_override_router4_default_level2_override5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-5": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "402": {"description": "Client error level 2"},
+ "405": {"description": "Client error level 5"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "502": {"description": "Server error level 2"},
+ "505": {"description": "Server error level 5"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level3/level4/default5": {
- "get": {
- "tags": ["level3a", "level3b", "level4a", "level4b"],
- "summary": "Path5 Default Router4 Override",
- "operationId": "path5_default_router4_override_level3_level4_default5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-4": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "403": {"description": "Client error level 3"},
- "404": {"description": "Client error level 4"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "503": {"description": "Server error level 3"},
- "504": {"description": "Server error level 4"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback5": {
+ "/": {
+ "get": {
+ "summary": "Callback5",
+ "operationId": "callback5__get",
+ "parameters": [
+ {
+ "name": "level5",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level5",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback4": {
- "/": {
- "get": {
- "summary": "Callback4",
- "operationId": "callback4__get",
- "parameters": [
- {
- "name": "level4",
- "in": "query",
- "required": True,
- "schema": {"title": "Level4", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level2/default5": {
+ "get": {
+ "tags": ["level2a", "level2b"],
+ "summary": "Path5 Default Router4 Default",
+ "operationId": "path5_default_router4_default_level2_default5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-2": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "402": {"description": "Client error level 2"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "502": {"description": "Server error level 2"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level3/override5": {
- "get": {
- "tags": ["level3a", "level3b", "path5a", "path5b"],
- "summary": "Path5 Override Router4 Default",
- "operationId": "path5_override_router4_default_level3_override5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-5": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "403": {"description": "Client error level 3"},
- "405": {"description": "Client error level 5"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ },
+ "callback2": {
+ "/": {
+ "get": {
+ "summary": "Callback2",
+ "operationId": "callback2__get",
+ "parameters": [
+ {
+ "name": "level2",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level2",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
}
}
},
},
- "500": {"description": "Server error level 0"},
- "503": {"description": "Server error level 3"},
- "505": {"description": "Server error level 5"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/override3": {
+ "get": {
+ "tags": ["path3a", "path3b"],
+ "summary": "Path3 Override Router2 Default",
+ "operationId": "path3_override_router2_default_override3_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level3", "type": "string"},
+ "name": "level3",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-3": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "403": {"description": "Client error level 3"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "503": {"description": "Server error level 3"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ }
+ },
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/default3": {
+ "get": {
+ "summary": "Path3 Default Router2 Default",
+ "operationId": "path3_default_router2_default_default3_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level3", "type": "string"},
+ "name": "level3",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-0": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
}
},
- "callback5": {
- "/": {
- "get": {
- "summary": "Callback5",
- "operationId": "callback5__get",
- "parameters": [
- {
- "name": "level5",
- "in": "query",
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
+ }
+ },
+ "/level3/level4/override5": {
+ "get": {
+ "tags": [
+ "level3a",
+ "level3b",
+ "level4a",
+ "level4b",
+ "path5a",
+ "path5b",
+ ],
+ "summary": "Path5 Override Router4 Override",
+ "operationId": "path5_override_router4_override_level3_level4_override5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-5": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "403": {"description": "Client error level 3"},
+ "404": {"description": "Client error level 4"},
+ "405": {"description": "Client error level 5"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "503": {"description": "Server error level 3"},
+ "504": {"description": "Server error level 4"},
+ "505": {"description": "Server error level 5"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level3/default5": {
- "get": {
- "tags": ["level3a", "level3b"],
- "summary": "Path5 Default Router4 Default",
- "operationId": "path5_default_router4_default_level3_default5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-3": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "403": {"description": "Client error level 3"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
}
}
},
- },
- "500": {"description": "Server error level 0"},
- "503": {"description": "Server error level 3"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback3": {
- "/": {
- "get": {
- "summary": "Callback3",
- "operationId": "callback3__get",
- "parameters": [
- {
- "name": "level3",
- "in": "query",
- "required": True,
- "schema": {"title": "Level3", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ },
+ "callback4": {
+ "/": {
+ "get": {
+ "summary": "Callback4",
+ "operationId": "callback4__get",
+ "parameters": [
+ {
+ "name": "level4",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level4",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- },
- }
- },
- "/level4/override5": {
- "get": {
- "tags": ["level4a", "level4b", "path5a", "path5b"],
- "summary": "Path5 Override Router4 Override",
- "operationId": "path5_override_router4_override_level4_override5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-5": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "404": {"description": "Client error level 4"},
- "405": {"description": "Client error level 5"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ },
+ "callback5": {
+ "/": {
+ "get": {
+ "summary": "Callback5",
+ "operationId": "callback5__get",
+ "parameters": [
+ {
+ "name": "level5",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level5",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
}
}
},
},
- "500": {"description": "Server error level 0"},
- "504": {"description": "Server error level 4"},
- "505": {"description": "Server error level 5"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level3/level4/default5": {
+ "get": {
+ "tags": ["level3a", "level3b", "level4a", "level4b"],
+ "summary": "Path5 Default Router4 Override",
+ "operationId": "path5_default_router4_override_level3_level4_default5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-4": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "403": {"description": "Client error level 3"},
+ "404": {"description": "Client error level 4"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "503": {"description": "Server error level 3"},
+ "504": {"description": "Server error level 4"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- "callback4": {
- "/": {
- "get": {
- "summary": "Callback4",
- "operationId": "callback4__get",
- "parameters": [
- {
- "name": "level4",
- "in": "query",
- "required": True,
- "schema": {"title": "Level4", "type": "string"},
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ },
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ }
+ },
+ "callback4": {
+ "/": {
+ "get": {
+ "summary": "Callback4",
+ "operationId": "callback4__get",
+ "parameters": [
+ {
+ "name": "level4",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level4",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback5": {
- "/": {
- "get": {
- "summary": "Callback5",
- "operationId": "callback5__get",
- "parameters": [
- {
- "name": "level5",
- "in": "query",
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level3/override5": {
+ "get": {
+ "tags": ["level3a", "level3b", "path5a", "path5b"],
+ "summary": "Path5 Override Router4 Default",
+ "operationId": "path5_override_router4_default_level3_override5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-5": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "403": {"description": "Client error level 3"},
+ "405": {"description": "Client error level 5"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "503": {"description": "Server error level 3"},
+ "505": {"description": "Server error level 5"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ }
+ },
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- },
- "deprecated": True,
- }
- },
- "/level4/default5": {
- "get": {
- "tags": ["level4a", "level4b"],
- "summary": "Path5 Default Router4 Override",
- "operationId": "path5_default_router4_override_level4_default5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-4": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "404": {"description": "Client error level 4"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ },
+ "callback5": {
+ "/": {
+ "get": {
+ "summary": "Callback5",
+ "operationId": "callback5__get",
+ "parameters": [
+ {
+ "name": "level5",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level5",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
}
}
},
},
- "500": {"description": "Server error level 0"},
- "504": {"description": "Server error level 4"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level3/default5": {
+ "get": {
+ "tags": ["level3a", "level3b"],
+ "summary": "Path5 Default Router4 Default",
+ "operationId": "path5_default_router4_default_level3_default5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-3": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "403": {"description": "Client error level 3"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "503": {"description": "Server error level 3"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ }
+ },
+ "callback3": {
+ "/": {
+ "get": {
+ "summary": "Callback3",
+ "operationId": "callback3__get",
+ "parameters": [
+ {
+ "name": "level3",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level3",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback4": {
- "/": {
- "get": {
- "summary": "Callback4",
- "operationId": "callback4__get",
- "parameters": [
- {
- "name": "level4",
- "in": "query",
- "required": True,
- "schema": {"title": "Level4", "type": "string"},
+ }
+ },
+ "/level4/override5": {
+ "get": {
+ "tags": ["level4a", "level4b", "path5a", "path5b"],
+ "summary": "Path5 Override Router4 Override",
+ "operationId": "path5_override_router4_override_level4_override5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-5": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "404": {"description": "Client error level 4"},
+ "405": {"description": "Client error level 5"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "504": {"description": "Server error level 4"},
+ "505": {"description": "Server error level 5"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ }
+ },
+ "callback4": {
+ "/": {
+ "get": {
+ "summary": "Callback4",
+ "operationId": "callback4__get",
+ "parameters": [
+ {
+ "name": "level4",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level4",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- },
- "deprecated": True,
- }
- },
- "/override5": {
- "get": {
- "tags": ["path5a", "path5b"],
- "summary": "Path5 Override Router4 Default",
- "operationId": "path5_override_router4_default_override5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-5": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "405": {"description": "Client error level 5"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ },
+ "callback5": {
+ "/": {
+ "get": {
+ "summary": "Callback5",
+ "operationId": "callback5__get",
+ "parameters": [
+ {
+ "name": "level5",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level5",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
}
}
},
},
- "500": {"description": "Server error level 0"},
- "505": {"description": "Server error level 5"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/level4/default5": {
+ "get": {
+ "tags": ["level4a", "level4b"],
+ "summary": "Path5 Default Router4 Override",
+ "operationId": "path5_default_router4_override_level4_default5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-4": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "404": {"description": "Client error level 4"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "504": {"description": "Server error level 4"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ }
+ },
+ "callback4": {
+ "/": {
+ "get": {
+ "summary": "Callback4",
+ "operationId": "callback4__get",
+ "parameters": [
+ {
+ "name": "level4",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level4",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
+ },
},
- "callback5": {
- "/": {
- "get": {
- "summary": "Callback5",
- "operationId": "callback5__get",
- "parameters": [
- {
- "name": "level5",
- "in": "query",
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/override5": {
+ "get": {
+ "tags": ["path5a", "path5b"],
+ "summary": "Path5 Override Router4 Default",
+ "operationId": "path5_override_router4_default_override5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-5": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "405": {"description": "Client error level 5"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ "505": {"description": "Server error level 5"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
- }
- },
- },
- "deprecated": True,
- }
- },
- "/default5": {
- "get": {
- "summary": "Path5 Default Router4 Default",
- "operationId": "path5_default_router4_default_default5_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Level5", "type": "string"},
- "name": "level5",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/x-level-0": {"schema": {}}},
- },
- "400": {"description": "Client error level 0"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ },
+ "callback5": {
+ "/": {
+ "get": {
+ "summary": "Callback5",
+ "operationId": "callback5__get",
+ "parameters": [
+ {
+ "name": "level5",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level5",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
}
}
},
},
- "500": {"description": "Server error level 0"},
- },
- "callbacks": {
- "callback0": {
- "/": {
- "get": {
- "summary": "Callback0",
- "operationId": "callback0__get",
- "parameters": [
- {
- "name": "level0",
- "in": "query",
- "required": True,
- "schema": {"title": "Level0", "type": "string"},
+ "deprecated": True,
+ }
+ },
+ "/default5": {
+ "get": {
+ "summary": "Path5 Default Router4 Default",
+ "operationId": "path5_default_router4_default_default5_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Level5", "type": "string"},
+ "name": "level5",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/x-level-0": {"schema": {}}},
+ },
+ "400": {"description": "Client error level 0"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
+ }
+ },
+ },
+ "500": {"description": "Server error level 0"},
+ },
+ "callbacks": {
+ "callback0": {
+ "/": {
+ "get": {
+ "summary": "Callback0",
+ "operationId": "callback0__get",
+ "parameters": [
+ {
+ "name": "level0",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "title": "Level0",
+ "type": "string",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
}
- }
- },
- }
+ },
+ }
+ },
},
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
},
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
},
- },
- }
- },
-}
+ }
+ },
+ }
diff --git a/tests/test_modules_same_name_body/test_main.py b/tests/test_modules_same_name_body/test_main.py
index 8b1aea031..1ebcaee8c 100644
--- a/tests/test_modules_same_name_body/test_main.py
+++ b/tests/test_modules_same_name_body/test_main.py
@@ -4,130 +4,6 @@ from .app.main import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/a/compute": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Compute",
- "operationId": "compute_a_compute_post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Body_compute_a_compute_post"
- }
- }
- },
- "required": True,
- },
- }
- },
- "/b/compute/": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Compute",
- "operationId": "compute_b_compute__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Body_compute_b_compute__post"
- }
- }
- },
- "required": True,
- },
- }
- },
- },
- "components": {
- "schemas": {
- "Body_compute_b_compute__post": {
- "title": "Body_compute_b_compute__post",
- "required": ["a", "b"],
- "type": "object",
- "properties": {
- "a": {"title": "A", "type": "integer"},
- "b": {"title": "B", "type": "string"},
- },
- },
- "Body_compute_a_compute_post": {
- "title": "Body_compute_a_compute_post",
- "required": ["a", "b"],
- "type": "object",
- "properties": {
- "a": {"title": "A", "type": "integer"},
- "b": {"title": "B", "type": "string"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_post_a():
data = {"a": 2, "b": "foo"}
@@ -153,3 +29,127 @@ def test_post_b_invalid():
data = {"a": "bar", "b": "foo"}
response = client.post("/b/compute/", json=data)
assert response.status_code == 422, response.text
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/a/compute": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Compute",
+ "operationId": "compute_a_compute_post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_compute_a_compute_post"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ },
+ "/b/compute/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Compute",
+ "operationId": "compute_b_compute__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_compute_b_compute__post"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_compute_b_compute__post": {
+ "title": "Body_compute_b_compute__post",
+ "required": ["a", "b"],
+ "type": "object",
+ "properties": {
+ "a": {"title": "A", "type": "integer"},
+ "b": {"title": "B", "type": "string"},
+ },
+ },
+ "Body_compute_a_compute_post": {
+ "title": "Body_compute_a_compute_post",
+ "required": ["a", "b"],
+ "type": "object",
+ "properties": {
+ "a": {"title": "A", "type": "integer"},
+ "b": {"title": "B", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_multi_body_errors.py b/tests/test_multi_body_errors.py
index 31308ea85..358684bc5 100644
--- a/tests/test_multi_body_errors.py
+++ b/tests/test_multi_body_errors.py
@@ -21,85 +21,6 @@ def save_item_no_body(item: List[Item]):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Save Item No Body",
- "operationId": "save_item_no_body_items__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "title": "Item",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Item"},
- }
- }
- },
- "required": True,
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "age"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "age": {"title": "Age", "exclusiveMinimum": 0.0, "type": "number"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
single_error = {
"detail": [
{
@@ -137,12 +58,6 @@ multiple_errors = {
}
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
def test_put_correct_body():
response = client.post("/items/", json=[{"name": "Foo", "age": 5}])
assert response.status_code == 200, response.text
@@ -159,3 +74,92 @@ def test_put_incorrect_body_multiple():
response = client.post("/items/", json=[{"age": "five"}, {"age": "six"}])
assert response.status_code == 422, response.text
assert response.json() == multiple_errors
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Save Item No Body",
+ "operationId": "save_item_no_body_items__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Item",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "age"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "age": {
+ "title": "Age",
+ "exclusiveMinimum": 0.0,
+ "type": "number",
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_multi_query_errors.py b/tests/test_multi_query_errors.py
index 3da461af5..e7a833f2b 100644
--- a/tests/test_multi_query_errors.py
+++ b/tests/test_multi_query_errors.py
@@ -14,76 +14,6 @@ def read_items(q: List[int] = Query(default=None)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": False,
- "schema": {
- "title": "Q",
- "type": "array",
- "items": {"type": "integer"},
- },
- "name": "q",
- "in": "query",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
multiple_errors = {
"detail": [
{
@@ -100,12 +30,6 @@ multiple_errors = {
}
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
def test_multi_query():
response = client.get("/items/?q=5&q=6")
assert response.status_code == 200, response.text
@@ -116,3 +40,79 @@ def test_multi_query_incorrect():
response = client.get("/items/?q=five&q=six")
assert response.status_code == 422, response.text
assert response.json() == multiple_errors
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Q",
+ "type": "array",
+ "items": {"type": "integer"},
+ },
+ "name": "q",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_openapi_query_parameter_extension.py b/tests/test_openapi_query_parameter_extension.py
index d3996f26e..8a9086ebe 100644
--- a/tests/test_openapi_query_parameter_extension.py
+++ b/tests/test_openapi_query_parameter_extension.py
@@ -32,96 +32,95 @@ def route_with_extra_query_parameters(standard_query_param: Optional[int] = 50):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/": {
- "get": {
- "summary": "Route With Extra Query Parameters",
- "operationId": "route_with_extra_query_parameters__get",
- "parameters": [
- {
- "required": False,
- "schema": {
- "title": "Standard Query Param",
- "type": "integer",
- "default": 50,
+def test_get_route():
+ response = client.get("/")
+ assert response.status_code == 200, response.text
+ assert response.json() == {}
+
+
+def test_openapi():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/": {
+ "get": {
+ "summary": "Route With Extra Query Parameters",
+ "operationId": "route_with_extra_query_parameters__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Standard Query Param",
+ "type": "integer",
+ "default": 50,
+ },
+ "name": "standard_query_param",
+ "in": "query",
},
- "name": "standard_query_param",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Extra Param 1"},
- "name": "extra_param_1",
- "in": "query",
- },
- {
- "required": True,
- "schema": {"title": "Extra Param 2"},
- "name": "extra_param_2",
- "in": "query",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ {
+ "required": False,
+ "schema": {"title": "Extra Param 1"},
+ "name": "extra_param_1",
+ "in": "query",
+ },
+ {
+ "required": True,
+ "schema": {"title": "Extra Param 2"},
+ "name": "extra_param_2",
+ "in": "query",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
+ }
}
- }
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
},
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
},
- },
- }
- },
-}
-
-
-def test_openapi():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
-def test_get_route():
- response = client.get("/")
- assert response.status_code == 200, response.text
- assert response.json() == {}
+ }
+ },
+ }
diff --git a/tests/test_openapi_route_extensions.py b/tests/test_openapi_route_extensions.py
index 8a1080d69..943dc43f2 100644
--- a/tests/test_openapi_route_extensions.py
+++ b/tests/test_openapi_route_extensions.py
@@ -12,34 +12,31 @@ def route_with_extras():
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- },
- "summary": "Route With Extras",
- "operationId": "route_with_extras__get",
- "x-custom-extension": "value",
- }
- },
- },
-}
+def test_get_route():
+ response = client.get("/")
+ assert response.status_code == 200, response.text
+ assert response.json() == {}
def test_openapi():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
-def test_get_route():
- response = client.get("/")
- assert response.status_code == 200, response.text
- assert response.json() == {}
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ },
+ "summary": "Route With Extras",
+ "operationId": "route_with_extras__get",
+ "x-custom-extension": "value",
+ }
+ },
+ },
+ }
diff --git a/tests/test_openapi_servers.py b/tests/test_openapi_servers.py
index a210154f6..26abeaa12 100644
--- a/tests/test_openapi_servers.py
+++ b/tests/test_openapi_servers.py
@@ -21,40 +21,37 @@ def foo():
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "servers": [
- {"url": "/", "description": "Default, relative server"},
- {
- "url": "http://staging.localhost.tiangolo.com:8000",
- "description": "Staging but actually localhost still",
- },
- {"url": "https://prod.example.com"},
- ],
- "paths": {
- "/foo": {
- "get": {
- "summary": "Foo",
- "operationId": "foo_foo_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- }
- }
- },
-}
-
-
-def test_openapi_servers():
- response = client.get("/openapi.json")
+def test_app():
+ response = client.get("/foo")
assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-def test_app():
- response = client.get("/foo")
+def test_openapi_schema():
+ response = client.get("/openapi.json")
assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "servers": [
+ {"url": "/", "description": "Default, relative server"},
+ {
+ "url": "http://staging.localhost.tiangolo.com:8000",
+ "description": "Staging but actually localhost still",
+ },
+ {"url": "https://prod.example.com"},
+ ],
+ "paths": {
+ "/foo": {
+ "get": {
+ "summary": "Foo",
+ "operationId": "foo_foo_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ }
+ },
+ }
diff --git a/tests/test_param_in_path_and_dependency.py b/tests/test_param_in_path_and_dependency.py
index 4d85afbce..0aef7ac7b 100644
--- a/tests/test_param_in_path_and_dependency.py
+++ b/tests/test_param_in_path_and_dependency.py
@@ -15,79 +15,79 @@ async def read_users(user_id: int):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/{user_id}": {
- "get": {
- "summary": "Read Users",
- "operationId": "read_users_users__user_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "User Id", "type": "integer"},
- "name": "user_id",
- "in": "path",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+
+def test_read_users():
+ response = client.get("/users/42")
+ assert response.status_code == 200, response.text
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ data = response.json()
+ assert data == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/{user_id}": {
+ "get": {
+ "summary": "Read Users",
+ "operationId": "read_users_users__user_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "User Id", "type": "integer"},
+ "name": "user_id",
+ "in": "path",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
+ }
}
- }
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
},
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
},
- },
- }
- },
-}
-
-
-def test_reused_param():
- response = client.get("/openapi.json")
- data = response.json()
- assert data == openapi_schema
-
-
-def test_read_users():
- response = client.get("/users/42")
- assert response.status_code == 200, response.text
+ }
+ },
+ }
diff --git a/tests/test_params_repr.py b/tests/test_params_repr.py
index d721257d7..d8dca1ea4 100644
--- a/tests/test_params_repr.py
+++ b/tests/test_params_repr.py
@@ -19,8 +19,9 @@ def test_param_repr(params):
assert repr(Param(params)) == "Param(" + str(params) + ")"
-def test_path_repr(params):
- assert repr(Path(params)) == "Path(Ellipsis)"
+def test_path_repr():
+ assert repr(Path()) == "Path(Ellipsis)"
+ assert repr(Path(...)) == "Path(Ellipsis)"
def test_query_repr(params):
diff --git a/tests/test_path.py b/tests/test_path.py
index d1a58bc66..03b93623a 100644
--- a/tests/test_path.py
+++ b/tests/test_path.py
@@ -193,7 +193,6 @@ response_less_than_equal_3 = {
("/path/bool/False", 200, False),
("/path/bool/false", 200, False),
("/path/param/foo", 200, "foo"),
- ("/path/param-required/foo", 200, "foo"),
("/path/param-minlength/foo", 200, "foo"),
("/path/param-minlength/fo", 422, response_at_least_3),
("/path/param-maxlength/foo", 200, "foo"),
diff --git a/tests/test_put_no_body.py b/tests/test_put_no_body.py
index 3da294ccf..a02d1152c 100644
--- a/tests/test_put_no_body.py
+++ b/tests/test_put_no_body.py
@@ -12,79 +12,6 @@ def save_item_no_body(item_id: str):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "put": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Save Item No Body",
- "operationId": "save_item_no_body_items__item_id__put",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
def test_put_no_body():
response = client.put("/items/foo")
assert response.status_code == 200, response.text
@@ -95,3 +22,75 @@ def test_put_no_body_with_body():
response = client.put("/items/foo", json={"name": "Foo"})
assert response.status_code == 200, response.text
assert response.json() == {"item_id": "foo"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Save Item No Body",
+ "operationId": "save_item_no_body_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_repeated_parameter_alias.py b/tests/test_repeated_parameter_alias.py
index 823f53a95..c656a161d 100644
--- a/tests/test_repeated_parameter_alias.py
+++ b/tests/test_repeated_parameter_alias.py
@@ -14,87 +14,87 @@ def get_parameters_with_repeated_aliases(
client = TestClient(app)
-openapi_schema = {
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "properties": {
- "detail": {
- "items": {"$ref": "#/components/schemas/ValidationError"},
- "title": "Detail",
- "type": "array",
- }
- },
- "title": "HTTPValidationError",
- "type": "object",
- },
- "ValidationError": {
- "properties": {
- "loc": {
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- "title": "Location",
- "type": "array",
+
+def test_get_parameters():
+ response = client.get("/test_path", params={"repeated_alias": "test_query"})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"path": "test_path", "query": "test_query"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == status.HTTP_200_OK
+ actual_schema = response.json()
+ assert actual_schema == {
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "properties": {
+ "detail": {
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ "title": "Detail",
+ "type": "array",
+ }
},
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
+ "title": "HTTPValidationError",
+ "type": "object",
},
- "required": ["loc", "msg", "type"],
- "title": "ValidationError",
- "type": "object",
- },
- }
- },
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "openapi": "3.0.2",
- "paths": {
- "/{repeated_alias}": {
- "get": {
- "operationId": "get_parameters_with_repeated_aliases__repeated_alias__get",
- "parameters": [
- {
- "in": "path",
- "name": "repeated_alias",
- "required": True,
- "schema": {"title": "Repeated Alias", "type": "string"},
- },
- {
- "in": "query",
- "name": "repeated_alias",
- "required": True,
- "schema": {"title": "Repeated Alias", "type": "string"},
- },
- ],
- "responses": {
- "200": {
- "content": {"application/json": {"schema": {}}},
- "description": "Successful Response",
+ "ValidationError": {
+ "properties": {
+ "loc": {
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ "title": "Location",
+ "type": "array",
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
},
- "422": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "required": ["loc", "msg", "type"],
+ "title": "ValidationError",
+ "type": "object",
+ },
+ }
+ },
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "openapi": "3.0.2",
+ "paths": {
+ "/{repeated_alias}": {
+ "get": {
+ "operationId": "get_parameters_with_repeated_aliases__repeated_alias__get",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "repeated_alias",
+ "required": True,
+ "schema": {"title": "Repeated Alias", "type": "string"},
+ },
+ {
+ "in": "query",
+ "name": "repeated_alias",
+ "required": True,
+ "schema": {"title": "Repeated Alias", "type": "string"},
+ },
+ ],
+ "responses": {
+ "200": {
+ "content": {"application/json": {"schema": {}}},
+ "description": "Successful Response",
+ },
+ "422": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
+ "description": "Validation Error",
},
- "description": "Validation Error",
},
- },
- "summary": "Get Parameters With Repeated Aliases",
+ "summary": "Get Parameters With Repeated Aliases",
+ }
}
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == status.HTTP_200_OK
- actual_schema = response.json()
- assert actual_schema == openapi_schema
-
-
-def test_get_parameters():
- response = client.get("/test_path", params={"repeated_alias": "test_query"})
- assert response.status_code == 200, response.text
- assert response.json() == {"path": "test_path", "query": "test_query"}
+ },
+ }
diff --git a/tests/test_reponse_set_reponse_code_empty.py b/tests/test_reponse_set_reponse_code_empty.py
index 094d54a84..14770fed0 100644
--- a/tests/test_reponse_set_reponse_code_empty.py
+++ b/tests/test_reponse_set_reponse_code_empty.py
@@ -9,6 +9,7 @@ app = FastAPI()
@app.delete(
"/{id}",
status_code=204,
+ response_model=None,
)
async def delete_deployment(
id: int,
@@ -21,77 +22,76 @@ async def delete_deployment(
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/{id}": {
- "delete": {
- "summary": "Delete Deployment",
- "operationId": "delete_deployment__id__delete",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Id", "type": "integer"},
- "name": "id",
- "in": "path",
- }
- ],
- "responses": {
- "204": {"description": "Successful Response"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+def test_dependency_set_status_code():
+ response = client.delete("/1")
+ assert response.status_code == 400 and response.content
+ assert response.json() == {"msg": "Status overwritten", "id": 1}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/{id}": {
+ "delete": {
+ "summary": "Delete Deployment",
+ "operationId": "delete_deployment__id__delete",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Id", "type": "integer"},
+ "name": "id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "204": {"description": "Successful Response"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
+ }
}
- }
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
},
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
},
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
-def test_dependency_set_status_code():
- response = client.delete("/1")
- assert response.status_code == 400 and response.content
- assert response.json() == {"msg": "Status overwritten", "id": 1}
+ }
+ },
+ }
diff --git a/tests/test_request_body_parameters_media_type.py b/tests/test_request_body_parameters_media_type.py
index e9cf4006d..32f6c6a72 100644
--- a/tests/test_request_body_parameters_media_type.py
+++ b/tests/test_request_body_parameters_media_type.py
@@ -33,36 +33,146 @@ async def create_shop(
pass # pragma: no cover
-create_product_request_body = {
- "content": {
- "application/vnd.api+json": {
- "schema": {"$ref": "#/components/schemas/Body_create_product_products_post"}
- }
- },
- "required": True,
-}
-
-create_shop_request_body = {
- "content": {
- "application/vnd.api+json": {
- "schema": {"$ref": "#/components/schemas/Body_create_shop_shops_post"}
- }
- },
- "required": True,
-}
-
client = TestClient(app)
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
- openapi_schema = response.json()
- assert (
- openapi_schema["paths"]["/products"]["post"]["requestBody"]
- == create_product_request_body
- )
- assert (
- openapi_schema["paths"]["/shops"]["post"]["requestBody"]
- == create_shop_request_body
- )
+ # insert_assert(response.json())
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/products": {
+ "post": {
+ "summary": "Create Product",
+ "operationId": "create_product_products_post",
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_product_products_post"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/shops": {
+ "post": {
+ "summary": "Create Shop",
+ "operationId": "create_shop_shops_post",
+ "requestBody": {
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_shop_shops_post"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_create_product_products_post": {
+ "title": "Body_create_product_products_post",
+ "required": ["data"],
+ "type": "object",
+ "properties": {"data": {"$ref": "#/components/schemas/Product"}},
+ },
+ "Body_create_shop_shops_post": {
+ "title": "Body_create_shop_shops_post",
+ "required": ["data"],
+ "type": "object",
+ "properties": {
+ "data": {"$ref": "#/components/schemas/Shop"},
+ "included": {
+ "title": "Included",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Product"},
+ "default": [],
+ },
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "Product": {
+ "title": "Product",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ },
+ },
+ "Shop": {
+ "title": "Shop",
+ "required": ["name"],
+ "type": "object",
+ "properties": {"name": {"title": "Name", "type": "string"}},
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_response_by_alias.py b/tests/test_response_by_alias.py
index de45e0880..1861a40fa 100644
--- a/tests/test_response_by_alias.py
+++ b/tests/test_response_by_alias.py
@@ -68,198 +68,9 @@ def no_alias_list():
return [{"name": "Foo"}, {"name": "Bar"}]
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/dict": {
- "get": {
- "summary": "Read Dict",
- "operationId": "read_dict_dict_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Model"}
- }
- },
- }
- },
- }
- },
- "/model": {
- "get": {
- "summary": "Read Model",
- "operationId": "read_model_model_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Model"}
- }
- },
- }
- },
- }
- },
- "/list": {
- "get": {
- "summary": "Read List",
- "operationId": "read_list_list_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Read List List Get",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Model"},
- }
- }
- },
- }
- },
- }
- },
- "/by-alias/dict": {
- "get": {
- "summary": "By Alias Dict",
- "operationId": "by_alias_dict_by_alias_dict_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Model"}
- }
- },
- }
- },
- }
- },
- "/by-alias/model": {
- "get": {
- "summary": "By Alias Model",
- "operationId": "by_alias_model_by_alias_model_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Model"}
- }
- },
- }
- },
- }
- },
- "/by-alias/list": {
- "get": {
- "summary": "By Alias List",
- "operationId": "by_alias_list_by_alias_list_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response By Alias List By Alias List Get",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Model"},
- }
- }
- },
- }
- },
- }
- },
- "/no-alias/dict": {
- "get": {
- "summary": "No Alias Dict",
- "operationId": "no_alias_dict_no_alias_dict_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/ModelNoAlias"}
- }
- },
- }
- },
- }
- },
- "/no-alias/model": {
- "get": {
- "summary": "No Alias Model",
- "operationId": "no_alias_model_no_alias_model_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/ModelNoAlias"}
- }
- },
- }
- },
- }
- },
- "/no-alias/list": {
- "get": {
- "summary": "No Alias List",
- "operationId": "no_alias_list_no_alias_list_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response No Alias List No Alias List Get",
- "type": "array",
- "items": {
- "$ref": "#/components/schemas/ModelNoAlias"
- },
- }
- }
- },
- }
- },
- }
- },
- },
- "components": {
- "schemas": {
- "Model": {
- "title": "Model",
- "required": ["alias"],
- "type": "object",
- "properties": {"alias": {"title": "Alias", "type": "string"}},
- },
- "ModelNoAlias": {
- "title": "ModelNoAlias",
- "required": ["name"],
- "type": "object",
- "properties": {"name": {"title": "Name", "type": "string"}},
- "description": "response_model_by_alias=False is basically a quick hack, to support proper OpenAPI use another model with the correct field names",
- },
- }
- },
-}
-
-
client = TestClient(app)
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
def test_read_dict():
response = client.get("/dict")
assert response.status_code == 200, response.text
@@ -321,3 +132,193 @@ def test_read_list_no_alias():
{"name": "Foo"},
{"name": "Bar"},
]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/dict": {
+ "get": {
+ "summary": "Read Dict",
+ "operationId": "read_dict_dict_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Model"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/model": {
+ "get": {
+ "summary": "Read Model",
+ "operationId": "read_model_model_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Model"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/list": {
+ "get": {
+ "summary": "Read List",
+ "operationId": "read_list_list_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Read List List Get",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Model"},
+ }
+ }
+ },
+ }
+ },
+ }
+ },
+ "/by-alias/dict": {
+ "get": {
+ "summary": "By Alias Dict",
+ "operationId": "by_alias_dict_by_alias_dict_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Model"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/by-alias/model": {
+ "get": {
+ "summary": "By Alias Model",
+ "operationId": "by_alias_model_by_alias_model_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Model"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/by-alias/list": {
+ "get": {
+ "summary": "By Alias List",
+ "operationId": "by_alias_list_by_alias_list_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response By Alias List By Alias List Get",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Model"},
+ }
+ }
+ },
+ }
+ },
+ }
+ },
+ "/no-alias/dict": {
+ "get": {
+ "summary": "No Alias Dict",
+ "operationId": "no_alias_dict_no_alias_dict_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ModelNoAlias"
+ }
+ }
+ },
+ }
+ },
+ }
+ },
+ "/no-alias/model": {
+ "get": {
+ "summary": "No Alias Model",
+ "operationId": "no_alias_model_no_alias_model_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ModelNoAlias"
+ }
+ }
+ },
+ }
+ },
+ }
+ },
+ "/no-alias/list": {
+ "get": {
+ "summary": "No Alias List",
+ "operationId": "no_alias_list_no_alias_list_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response No Alias List No Alias List Get",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ModelNoAlias"
+ },
+ }
+ }
+ },
+ }
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Model": {
+ "title": "Model",
+ "required": ["alias"],
+ "type": "object",
+ "properties": {"alias": {"title": "Alias", "type": "string"}},
+ },
+ "ModelNoAlias": {
+ "title": "ModelNoAlias",
+ "required": ["name"],
+ "type": "object",
+ "properties": {"name": {"title": "Name", "type": "string"}},
+ "description": "response_model_by_alias=False is basically a quick hack, to support proper OpenAPI use another model with the correct field names",
+ },
+ }
+ },
+ }
diff --git a/tests/test_response_class_no_mediatype.py b/tests/test_response_class_no_mediatype.py
index eb8500f3a..2d75c7535 100644
--- a/tests/test_response_class_no_mediatype.py
+++ b/tests/test_response_class_no_mediatype.py
@@ -35,80 +35,79 @@ async def b():
pass # pragma: no cover
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/a": {
- "get": {
- "responses": {
- "500": {
- "description": "Error",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/JsonApiError"}
- }
+client = TestClient(app)
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/a": {
+ "get": {
+ "responses": {
+ "500": {
+ "description": "Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/JsonApiError"
+ }
+ }
+ },
},
+ "200": {"description": "Successful Response"},
},
- "200": {"description": "Successful Response"},
- },
- "summary": "A",
- "operationId": "a_a_get",
- }
- },
- "/b": {
- "get": {
- "responses": {
- "500": {
- "description": "Error",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Error"}
- }
+ "summary": "A",
+ "operationId": "a_a_get",
+ }
+ },
+ "/b": {
+ "get": {
+ "responses": {
+ "500": {
+ "description": "Error",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Error"}
+ }
+ },
+ },
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
},
},
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ "summary": "B",
+ "operationId": "b_b_get",
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Error": {
+ "title": "Error",
+ "required": ["status", "title"],
+ "type": "object",
+ "properties": {
+ "status": {"title": "Status", "type": "string"},
+ "title": {"title": "Title", "type": "string"},
+ },
+ },
+ "JsonApiError": {
+ "title": "JsonApiError",
+ "required": ["errors"],
+ "type": "object",
+ "properties": {
+ "errors": {
+ "title": "Errors",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Error"},
+ }
},
},
- "summary": "B",
- "operationId": "b_b_get",
}
},
- },
- "components": {
- "schemas": {
- "Error": {
- "title": "Error",
- "required": ["status", "title"],
- "type": "object",
- "properties": {
- "status": {"title": "Status", "type": "string"},
- "title": {"title": "Title", "type": "string"},
- },
- },
- "JsonApiError": {
- "title": "JsonApiError",
- "required": ["errors"],
- "type": "object",
- "properties": {
- "errors": {
- "title": "Errors",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Error"},
- }
- },
- },
- }
- },
-}
-
-
-client = TestClient(app)
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
+ }
diff --git a/tests/test_response_code_no_body.py b/tests/test_response_code_no_body.py
index 6d9b5c333..3851a325d 100644
--- a/tests/test_response_code_no_body.py
+++ b/tests/test_response_code_no_body.py
@@ -36,80 +36,79 @@ async def b():
pass # pragma: no cover
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/a": {
- "get": {
- "responses": {
- "500": {
- "description": "Error",
- "content": {
- "application/vnd.api+json": {
- "schema": {"$ref": "#/components/schemas/JsonApiError"}
- }
- },
- },
- "204": {"description": "Successful Response"},
- },
- "summary": "A",
- "operationId": "a_a_get",
- }
- },
- "/b": {
- "get": {
- "responses": {
- "204": {"description": "No Content"},
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- },
- "summary": "B",
- "operationId": "b_b_get",
- }
- },
- },
- "components": {
- "schemas": {
- "Error": {
- "title": "Error",
- "required": ["status", "title"],
- "type": "object",
- "properties": {
- "status": {"title": "Status", "type": "string"},
- "title": {"title": "Title", "type": "string"},
- },
- },
- "JsonApiError": {
- "title": "JsonApiError",
- "required": ["errors"],
- "type": "object",
- "properties": {
- "errors": {
- "title": "Errors",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Error"},
- }
- },
- },
- }
- },
-}
-
-
client = TestClient(app)
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
def test_get_response():
response = client.get("/a")
assert response.status_code == 204, response.text
assert "content-length" not in response.headers
assert response.content == b""
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/a": {
+ "get": {
+ "responses": {
+ "500": {
+ "description": "Error",
+ "content": {
+ "application/vnd.api+json": {
+ "schema": {
+ "$ref": "#/components/schemas/JsonApiError"
+ }
+ }
+ },
+ },
+ "204": {"description": "Successful Response"},
+ },
+ "summary": "A",
+ "operationId": "a_a_get",
+ }
+ },
+ "/b": {
+ "get": {
+ "responses": {
+ "204": {"description": "No Content"},
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ },
+ "summary": "B",
+ "operationId": "b_b_get",
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Error": {
+ "title": "Error",
+ "required": ["status", "title"],
+ "type": "object",
+ "properties": {
+ "status": {"title": "Status", "type": "string"},
+ "title": {"title": "Title", "type": "string"},
+ },
+ },
+ "JsonApiError": {
+ "title": "JsonApiError",
+ "required": ["errors"],
+ "type": "object",
+ "properties": {
+ "errors": {
+ "title": "Errors",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Error"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_response_model_as_return_annotation.py b/tests/test_response_model_as_return_annotation.py
new file mode 100644
index 000000000..7decdff7d
--- /dev/null
+++ b/tests/test_response_model_as_return_annotation.py
@@ -0,0 +1,1108 @@
+from typing import List, Union
+
+import pytest
+from fastapi import FastAPI
+from fastapi.exceptions import FastAPIError
+from fastapi.responses import JSONResponse, Response
+from fastapi.testclient import TestClient
+from pydantic import BaseModel, ValidationError
+
+
+class BaseUser(BaseModel):
+ name: str
+
+
+class User(BaseUser):
+ surname: str
+
+
+class DBUser(User):
+ password_hash: str
+
+
+class Item(BaseModel):
+ name: str
+ price: float
+
+
+app = FastAPI()
+
+
+@app.get("/no_response_model-no_annotation-return_model")
+def no_response_model_no_annotation_return_model():
+ return User(name="John", surname="Doe")
+
+
+@app.get("/no_response_model-no_annotation-return_dict")
+def no_response_model_no_annotation_return_dict():
+ return {"name": "John", "surname": "Doe"}
+
+
+@app.get("/response_model-no_annotation-return_same_model", response_model=User)
+def response_model_no_annotation_return_same_model():
+ return User(name="John", surname="Doe")
+
+
+@app.get("/response_model-no_annotation-return_exact_dict", response_model=User)
+def response_model_no_annotation_return_exact_dict():
+ return {"name": "John", "surname": "Doe"}
+
+
+@app.get("/response_model-no_annotation-return_invalid_dict", response_model=User)
+def response_model_no_annotation_return_invalid_dict():
+ return {"name": "John"}
+
+
+@app.get("/response_model-no_annotation-return_invalid_model", response_model=User)
+def response_model_no_annotation_return_invalid_model():
+ return Item(name="Foo", price=42.0)
+
+
+@app.get(
+ "/response_model-no_annotation-return_dict_with_extra_data", response_model=User
+)
+def response_model_no_annotation_return_dict_with_extra_data():
+ return {"name": "John", "surname": "Doe", "password_hash": "secret"}
+
+
+@app.get(
+ "/response_model-no_annotation-return_submodel_with_extra_data", response_model=User
+)
+def response_model_no_annotation_return_submodel_with_extra_data():
+ return DBUser(name="John", surname="Doe", password_hash="secret")
+
+
+@app.get("/no_response_model-annotation-return_same_model")
+def no_response_model_annotation_return_same_model() -> User:
+ return User(name="John", surname="Doe")
+
+
+@app.get("/no_response_model-annotation-return_exact_dict")
+def no_response_model_annotation_return_exact_dict() -> User:
+ return {"name": "John", "surname": "Doe"}
+
+
+@app.get("/no_response_model-annotation-return_invalid_dict")
+def no_response_model_annotation_return_invalid_dict() -> User:
+ return {"name": "John"}
+
+
+@app.get("/no_response_model-annotation-return_invalid_model")
+def no_response_model_annotation_return_invalid_model() -> User:
+ return Item(name="Foo", price=42.0)
+
+
+@app.get("/no_response_model-annotation-return_dict_with_extra_data")
+def no_response_model_annotation_return_dict_with_extra_data() -> User:
+ return {"name": "John", "surname": "Doe", "password_hash": "secret"}
+
+
+@app.get("/no_response_model-annotation-return_submodel_with_extra_data")
+def no_response_model_annotation_return_submodel_with_extra_data() -> User:
+ return DBUser(name="John", surname="Doe", password_hash="secret")
+
+
+@app.get("/response_model_none-annotation-return_same_model", response_model=None)
+def response_model_none_annotation_return_same_model() -> User:
+ return User(name="John", surname="Doe")
+
+
+@app.get("/response_model_none-annotation-return_exact_dict", response_model=None)
+def response_model_none_annotation_return_exact_dict() -> User:
+ return {"name": "John", "surname": "Doe"}
+
+
+@app.get("/response_model_none-annotation-return_invalid_dict", response_model=None)
+def response_model_none_annotation_return_invalid_dict() -> User:
+ return {"name": "John"}
+
+
+@app.get("/response_model_none-annotation-return_invalid_model", response_model=None)
+def response_model_none_annotation_return_invalid_model() -> User:
+ return Item(name="Foo", price=42.0)
+
+
+@app.get(
+ "/response_model_none-annotation-return_dict_with_extra_data", response_model=None
+)
+def response_model_none_annotation_return_dict_with_extra_data() -> User:
+ return {"name": "John", "surname": "Doe", "password_hash": "secret"}
+
+
+@app.get(
+ "/response_model_none-annotation-return_submodel_with_extra_data",
+ response_model=None,
+)
+def response_model_none_annotation_return_submodel_with_extra_data() -> User:
+ return DBUser(name="John", surname="Doe", password_hash="secret")
+
+
+@app.get(
+ "/response_model_model1-annotation_model2-return_same_model", response_model=User
+)
+def response_model_model1_annotation_model2_return_same_model() -> Item:
+ return User(name="John", surname="Doe")
+
+
+@app.get(
+ "/response_model_model1-annotation_model2-return_exact_dict", response_model=User
+)
+def response_model_model1_annotation_model2_return_exact_dict() -> Item:
+ return {"name": "John", "surname": "Doe"}
+
+
+@app.get(
+ "/response_model_model1-annotation_model2-return_invalid_dict", response_model=User
+)
+def response_model_model1_annotation_model2_return_invalid_dict() -> Item:
+ return {"name": "John"}
+
+
+@app.get(
+ "/response_model_model1-annotation_model2-return_invalid_model", response_model=User
+)
+def response_model_model1_annotation_model2_return_invalid_model() -> Item:
+ return Item(name="Foo", price=42.0)
+
+
+@app.get(
+ "/response_model_model1-annotation_model2-return_dict_with_extra_data",
+ response_model=User,
+)
+def response_model_model1_annotation_model2_return_dict_with_extra_data() -> Item:
+ return {"name": "John", "surname": "Doe", "password_hash": "secret"}
+
+
+@app.get(
+ "/response_model_model1-annotation_model2-return_submodel_with_extra_data",
+ response_model=User,
+)
+def response_model_model1_annotation_model2_return_submodel_with_extra_data() -> Item:
+ return DBUser(name="John", surname="Doe", password_hash="secret")
+
+
+@app.get(
+ "/response_model_filtering_model-annotation_submodel-return_submodel",
+ response_model=User,
+)
+def response_model_filtering_model_annotation_submodel_return_submodel() -> DBUser:
+ return DBUser(name="John", surname="Doe", password_hash="secret")
+
+
+@app.get("/response_model_list_of_model-no_annotation", response_model=List[User])
+def response_model_list_of_model_no_annotation():
+ return [
+ DBUser(name="John", surname="Doe", password_hash="secret"),
+ DBUser(name="Jane", surname="Does", password_hash="secret2"),
+ ]
+
+
+@app.get("/no_response_model-annotation_list_of_model")
+def no_response_model_annotation_list_of_model() -> List[User]:
+ return [
+ DBUser(name="John", surname="Doe", password_hash="secret"),
+ DBUser(name="Jane", surname="Does", password_hash="secret2"),
+ ]
+
+
+@app.get("/no_response_model-annotation_forward_ref_list_of_model")
+def no_response_model_annotation_forward_ref_list_of_model() -> "List[User]":
+ return [
+ DBUser(name="John", surname="Doe", password_hash="secret"),
+ DBUser(name="Jane", surname="Does", password_hash="secret2"),
+ ]
+
+
+@app.get(
+ "/response_model_union-no_annotation-return_model1",
+ response_model=Union[User, Item],
+)
+def response_model_union_no_annotation_return_model1():
+ return DBUser(name="John", surname="Doe", password_hash="secret")
+
+
+@app.get(
+ "/response_model_union-no_annotation-return_model2",
+ response_model=Union[User, Item],
+)
+def response_model_union_no_annotation_return_model2():
+ return Item(name="Foo", price=42.0)
+
+
+@app.get("/no_response_model-annotation_union-return_model1")
+def no_response_model_annotation_union_return_model1() -> Union[User, Item]:
+ return DBUser(name="John", surname="Doe", password_hash="secret")
+
+
+@app.get("/no_response_model-annotation_union-return_model2")
+def no_response_model_annotation_union_return_model2() -> Union[User, Item]:
+ return Item(name="Foo", price=42.0)
+
+
+@app.get("/no_response_model-annotation_response_class")
+def no_response_model_annotation_response_class() -> Response:
+ return Response(content="Foo")
+
+
+@app.get("/no_response_model-annotation_json_response_class")
+def no_response_model_annotation_json_response_class() -> JSONResponse:
+ return JSONResponse(content={"foo": "bar"})
+
+
+client = TestClient(app)
+
+
+def test_no_response_model_no_annotation_return_model():
+ response = client.get("/no_response_model-no_annotation-return_model")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_no_response_model_no_annotation_return_dict():
+ response = client.get("/no_response_model-no_annotation-return_dict")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_response_model_no_annotation_return_same_model():
+ response = client.get("/response_model-no_annotation-return_same_model")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_response_model_no_annotation_return_exact_dict():
+ response = client.get("/response_model-no_annotation-return_exact_dict")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_response_model_no_annotation_return_invalid_dict():
+ with pytest.raises(ValidationError):
+ client.get("/response_model-no_annotation-return_invalid_dict")
+
+
+def test_response_model_no_annotation_return_invalid_model():
+ with pytest.raises(ValidationError):
+ client.get("/response_model-no_annotation-return_invalid_model")
+
+
+def test_response_model_no_annotation_return_dict_with_extra_data():
+ response = client.get("/response_model-no_annotation-return_dict_with_extra_data")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_response_model_no_annotation_return_submodel_with_extra_data():
+ response = client.get(
+ "/response_model-no_annotation-return_submodel_with_extra_data"
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_no_response_model_annotation_return_same_model():
+ response = client.get("/no_response_model-annotation-return_same_model")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_no_response_model_annotation_return_exact_dict():
+ response = client.get("/no_response_model-annotation-return_exact_dict")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_no_response_model_annotation_return_invalid_dict():
+ with pytest.raises(ValidationError):
+ client.get("/no_response_model-annotation-return_invalid_dict")
+
+
+def test_no_response_model_annotation_return_invalid_model():
+ with pytest.raises(ValidationError):
+ client.get("/no_response_model-annotation-return_invalid_model")
+
+
+def test_no_response_model_annotation_return_dict_with_extra_data():
+ response = client.get("/no_response_model-annotation-return_dict_with_extra_data")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_no_response_model_annotation_return_submodel_with_extra_data():
+ response = client.get(
+ "/no_response_model-annotation-return_submodel_with_extra_data"
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_response_model_none_annotation_return_same_model():
+ response = client.get("/response_model_none-annotation-return_same_model")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_response_model_none_annotation_return_exact_dict():
+ response = client.get("/response_model_none-annotation-return_exact_dict")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_response_model_none_annotation_return_invalid_dict():
+ response = client.get("/response_model_none-annotation-return_invalid_dict")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John"}
+
+
+def test_response_model_none_annotation_return_invalid_model():
+ response = client.get("/response_model_none-annotation-return_invalid_model")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "Foo", "price": 42.0}
+
+
+def test_response_model_none_annotation_return_dict_with_extra_data():
+ response = client.get("/response_model_none-annotation-return_dict_with_extra_data")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "name": "John",
+ "surname": "Doe",
+ "password_hash": "secret",
+ }
+
+
+def test_response_model_none_annotation_return_submodel_with_extra_data():
+ response = client.get(
+ "/response_model_none-annotation-return_submodel_with_extra_data"
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "name": "John",
+ "surname": "Doe",
+ "password_hash": "secret",
+ }
+
+
+def test_response_model_model1_annotation_model2_return_same_model():
+ response = client.get("/response_model_model1-annotation_model2-return_same_model")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_response_model_model1_annotation_model2_return_exact_dict():
+ response = client.get("/response_model_model1-annotation_model2-return_exact_dict")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_response_model_model1_annotation_model2_return_invalid_dict():
+ with pytest.raises(ValidationError):
+ client.get("/response_model_model1-annotation_model2-return_invalid_dict")
+
+
+def test_response_model_model1_annotation_model2_return_invalid_model():
+ with pytest.raises(ValidationError):
+ client.get("/response_model_model1-annotation_model2-return_invalid_model")
+
+
+def test_response_model_model1_annotation_model2_return_dict_with_extra_data():
+ response = client.get(
+ "/response_model_model1-annotation_model2-return_dict_with_extra_data"
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_response_model_model1_annotation_model2_return_submodel_with_extra_data():
+ response = client.get(
+ "/response_model_model1-annotation_model2-return_submodel_with_extra_data"
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_response_model_filtering_model_annotation_submodel_return_submodel():
+ response = client.get(
+ "/response_model_filtering_model-annotation_submodel-return_submodel"
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_response_model_list_of_model_no_annotation():
+ response = client.get("/response_model_list_of_model-no_annotation")
+ assert response.status_code == 200, response.text
+ assert response.json() == [
+ {"name": "John", "surname": "Doe"},
+ {"name": "Jane", "surname": "Does"},
+ ]
+
+
+def test_no_response_model_annotation_list_of_model():
+ response = client.get("/no_response_model-annotation_list_of_model")
+ assert response.status_code == 200, response.text
+ assert response.json() == [
+ {"name": "John", "surname": "Doe"},
+ {"name": "Jane", "surname": "Does"},
+ ]
+
+
+def test_no_response_model_annotation_forward_ref_list_of_model():
+ response = client.get("/no_response_model-annotation_forward_ref_list_of_model")
+ assert response.status_code == 200, response.text
+ assert response.json() == [
+ {"name": "John", "surname": "Doe"},
+ {"name": "Jane", "surname": "Does"},
+ ]
+
+
+def test_response_model_union_no_annotation_return_model1():
+ response = client.get("/response_model_union-no_annotation-return_model1")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_response_model_union_no_annotation_return_model2():
+ response = client.get("/response_model_union-no_annotation-return_model2")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "Foo", "price": 42.0}
+
+
+def test_no_response_model_annotation_union_return_model1():
+ response = client.get("/no_response_model-annotation_union-return_model1")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "John", "surname": "Doe"}
+
+
+def test_no_response_model_annotation_union_return_model2():
+ response = client.get("/no_response_model-annotation_union-return_model2")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "Foo", "price": 42.0}
+
+
+def test_no_response_model_annotation_return_class():
+ response = client.get("/no_response_model-annotation_response_class")
+ assert response.status_code == 200, response.text
+ assert response.text == "Foo"
+
+
+def test_no_response_model_annotation_json_response_class():
+ response = client.get("/no_response_model-annotation_json_response_class")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"foo": "bar"}
+
+
+def test_invalid_response_model_field():
+ app = FastAPI()
+ with pytest.raises(FastAPIError) as e:
+
+ @app.get("/")
+ def read_root() -> Union[Response, None]:
+ return Response(content="Foo") # pragma: no cover
+
+ assert "valid Pydantic field type" in e.value.args[0]
+ assert "parameter response_model=None" in e.value.args[0]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/no_response_model-no_annotation-return_model": {
+ "get": {
+ "summary": "No Response Model No Annotation Return Model",
+ "operationId": "no_response_model_no_annotation_return_model_no_response_model_no_annotation_return_model_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ },
+ "/no_response_model-no_annotation-return_dict": {
+ "get": {
+ "summary": "No Response Model No Annotation Return Dict",
+ "operationId": "no_response_model_no_annotation_return_dict_no_response_model_no_annotation_return_dict_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ },
+ "/response_model-no_annotation-return_same_model": {
+ "get": {
+ "summary": "Response Model No Annotation Return Same Model",
+ "operationId": "response_model_no_annotation_return_same_model_response_model_no_annotation_return_same_model_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/response_model-no_annotation-return_exact_dict": {
+ "get": {
+ "summary": "Response Model No Annotation Return Exact Dict",
+ "operationId": "response_model_no_annotation_return_exact_dict_response_model_no_annotation_return_exact_dict_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/response_model-no_annotation-return_invalid_dict": {
+ "get": {
+ "summary": "Response Model No Annotation Return Invalid Dict",
+ "operationId": "response_model_no_annotation_return_invalid_dict_response_model_no_annotation_return_invalid_dict_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/response_model-no_annotation-return_invalid_model": {
+ "get": {
+ "summary": "Response Model No Annotation Return Invalid Model",
+ "operationId": "response_model_no_annotation_return_invalid_model_response_model_no_annotation_return_invalid_model_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/response_model-no_annotation-return_dict_with_extra_data": {
+ "get": {
+ "summary": "Response Model No Annotation Return Dict With Extra Data",
+ "operationId": "response_model_no_annotation_return_dict_with_extra_data_response_model_no_annotation_return_dict_with_extra_data_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/response_model-no_annotation-return_submodel_with_extra_data": {
+ "get": {
+ "summary": "Response Model No Annotation Return Submodel With Extra Data",
+ "operationId": "response_model_no_annotation_return_submodel_with_extra_data_response_model_no_annotation_return_submodel_with_extra_data_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/no_response_model-annotation-return_same_model": {
+ "get": {
+ "summary": "No Response Model Annotation Return Same Model",
+ "operationId": "no_response_model_annotation_return_same_model_no_response_model_annotation_return_same_model_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/no_response_model-annotation-return_exact_dict": {
+ "get": {
+ "summary": "No Response Model Annotation Return Exact Dict",
+ "operationId": "no_response_model_annotation_return_exact_dict_no_response_model_annotation_return_exact_dict_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/no_response_model-annotation-return_invalid_dict": {
+ "get": {
+ "summary": "No Response Model Annotation Return Invalid Dict",
+ "operationId": "no_response_model_annotation_return_invalid_dict_no_response_model_annotation_return_invalid_dict_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/no_response_model-annotation-return_invalid_model": {
+ "get": {
+ "summary": "No Response Model Annotation Return Invalid Model",
+ "operationId": "no_response_model_annotation_return_invalid_model_no_response_model_annotation_return_invalid_model_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/no_response_model-annotation-return_dict_with_extra_data": {
+ "get": {
+ "summary": "No Response Model Annotation Return Dict With Extra Data",
+ "operationId": "no_response_model_annotation_return_dict_with_extra_data_no_response_model_annotation_return_dict_with_extra_data_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/no_response_model-annotation-return_submodel_with_extra_data": {
+ "get": {
+ "summary": "No Response Model Annotation Return Submodel With Extra Data",
+ "operationId": "no_response_model_annotation_return_submodel_with_extra_data_no_response_model_annotation_return_submodel_with_extra_data_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/response_model_none-annotation-return_same_model": {
+ "get": {
+ "summary": "Response Model None Annotation Return Same Model",
+ "operationId": "response_model_none_annotation_return_same_model_response_model_none_annotation_return_same_model_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ },
+ "/response_model_none-annotation-return_exact_dict": {
+ "get": {
+ "summary": "Response Model None Annotation Return Exact Dict",
+ "operationId": "response_model_none_annotation_return_exact_dict_response_model_none_annotation_return_exact_dict_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ },
+ "/response_model_none-annotation-return_invalid_dict": {
+ "get": {
+ "summary": "Response Model None Annotation Return Invalid Dict",
+ "operationId": "response_model_none_annotation_return_invalid_dict_response_model_none_annotation_return_invalid_dict_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ },
+ "/response_model_none-annotation-return_invalid_model": {
+ "get": {
+ "summary": "Response Model None Annotation Return Invalid Model",
+ "operationId": "response_model_none_annotation_return_invalid_model_response_model_none_annotation_return_invalid_model_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ },
+ "/response_model_none-annotation-return_dict_with_extra_data": {
+ "get": {
+ "summary": "Response Model None Annotation Return Dict With Extra Data",
+ "operationId": "response_model_none_annotation_return_dict_with_extra_data_response_model_none_annotation_return_dict_with_extra_data_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ },
+ "/response_model_none-annotation-return_submodel_with_extra_data": {
+ "get": {
+ "summary": "Response Model None Annotation Return Submodel With Extra Data",
+ "operationId": "response_model_none_annotation_return_submodel_with_extra_data_response_model_none_annotation_return_submodel_with_extra_data_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ },
+ "/response_model_model1-annotation_model2-return_same_model": {
+ "get": {
+ "summary": "Response Model Model1 Annotation Model2 Return Same Model",
+ "operationId": "response_model_model1_annotation_model2_return_same_model_response_model_model1_annotation_model2_return_same_model_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/response_model_model1-annotation_model2-return_exact_dict": {
+ "get": {
+ "summary": "Response Model Model1 Annotation Model2 Return Exact Dict",
+ "operationId": "response_model_model1_annotation_model2_return_exact_dict_response_model_model1_annotation_model2_return_exact_dict_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/response_model_model1-annotation_model2-return_invalid_dict": {
+ "get": {
+ "summary": "Response Model Model1 Annotation Model2 Return Invalid Dict",
+ "operationId": "response_model_model1_annotation_model2_return_invalid_dict_response_model_model1_annotation_model2_return_invalid_dict_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/response_model_model1-annotation_model2-return_invalid_model": {
+ "get": {
+ "summary": "Response Model Model1 Annotation Model2 Return Invalid Model",
+ "operationId": "response_model_model1_annotation_model2_return_invalid_model_response_model_model1_annotation_model2_return_invalid_model_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/response_model_model1-annotation_model2-return_dict_with_extra_data": {
+ "get": {
+ "summary": "Response Model Model1 Annotation Model2 Return Dict With Extra Data",
+ "operationId": "response_model_model1_annotation_model2_return_dict_with_extra_data_response_model_model1_annotation_model2_return_dict_with_extra_data_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/response_model_model1-annotation_model2-return_submodel_with_extra_data": {
+ "get": {
+ "summary": "Response Model Model1 Annotation Model2 Return Submodel With Extra Data",
+ "operationId": "response_model_model1_annotation_model2_return_submodel_with_extra_data_response_model_model1_annotation_model2_return_submodel_with_extra_data_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/response_model_filtering_model-annotation_submodel-return_submodel": {
+ "get": {
+ "summary": "Response Model Filtering Model Annotation Submodel Return Submodel",
+ "operationId": "response_model_filtering_model_annotation_submodel_return_submodel_response_model_filtering_model_annotation_submodel_return_submodel_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/User"}
+ }
+ },
+ }
+ },
+ }
+ },
+ "/response_model_list_of_model-no_annotation": {
+ "get": {
+ "summary": "Response Model List Of Model No Annotation",
+ "operationId": "response_model_list_of_model_no_annotation_response_model_list_of_model_no_annotation_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Response Model List Of Model No Annotation Response Model List Of Model No Annotation Get",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/User"},
+ }
+ }
+ },
+ }
+ },
+ }
+ },
+ "/no_response_model-annotation_list_of_model": {
+ "get": {
+ "summary": "No Response Model Annotation List Of Model",
+ "operationId": "no_response_model_annotation_list_of_model_no_response_model_annotation_list_of_model_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response No Response Model Annotation List Of Model No Response Model Annotation List Of Model Get",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/User"},
+ }
+ }
+ },
+ }
+ },
+ }
+ },
+ "/no_response_model-annotation_forward_ref_list_of_model": {
+ "get": {
+ "summary": "No Response Model Annotation Forward Ref List Of Model",
+ "operationId": "no_response_model_annotation_forward_ref_list_of_model_no_response_model_annotation_forward_ref_list_of_model_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response No Response Model Annotation Forward Ref List Of Model No Response Model Annotation Forward Ref List Of Model Get",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/User"},
+ }
+ }
+ },
+ }
+ },
+ }
+ },
+ "/response_model_union-no_annotation-return_model1": {
+ "get": {
+ "summary": "Response Model Union No Annotation Return Model1",
+ "operationId": "response_model_union_no_annotation_return_model1_response_model_union_no_annotation_return_model1_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Response Model Union No Annotation Return Model1 Response Model Union No Annotation Return Model1 Get",
+ "anyOf": [
+ {"$ref": "#/components/schemas/User"},
+ {"$ref": "#/components/schemas/Item"},
+ ],
+ }
+ }
+ },
+ }
+ },
+ }
+ },
+ "/response_model_union-no_annotation-return_model2": {
+ "get": {
+ "summary": "Response Model Union No Annotation Return Model2",
+ "operationId": "response_model_union_no_annotation_return_model2_response_model_union_no_annotation_return_model2_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Response Model Union No Annotation Return Model2 Response Model Union No Annotation Return Model2 Get",
+ "anyOf": [
+ {"$ref": "#/components/schemas/User"},
+ {"$ref": "#/components/schemas/Item"},
+ ],
+ }
+ }
+ },
+ }
+ },
+ }
+ },
+ "/no_response_model-annotation_union-return_model1": {
+ "get": {
+ "summary": "No Response Model Annotation Union Return Model1",
+ "operationId": "no_response_model_annotation_union_return_model1_no_response_model_annotation_union_return_model1_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response No Response Model Annotation Union Return Model1 No Response Model Annotation Union Return Model1 Get",
+ "anyOf": [
+ {"$ref": "#/components/schemas/User"},
+ {"$ref": "#/components/schemas/Item"},
+ ],
+ }
+ }
+ },
+ }
+ },
+ }
+ },
+ "/no_response_model-annotation_union-return_model2": {
+ "get": {
+ "summary": "No Response Model Annotation Union Return Model2",
+ "operationId": "no_response_model_annotation_union_return_model2_no_response_model_annotation_union_return_model2_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response No Response Model Annotation Union Return Model2 No Response Model Annotation Union Return Model2 Get",
+ "anyOf": [
+ {"$ref": "#/components/schemas/User"},
+ {"$ref": "#/components/schemas/Item"},
+ ],
+ }
+ }
+ },
+ }
+ },
+ }
+ },
+ "/no_response_model-annotation_response_class": {
+ "get": {
+ "summary": "No Response Model Annotation Response Class",
+ "operationId": "no_response_model_annotation_response_class_no_response_model_annotation_response_class_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ },
+ "/no_response_model-annotation_json_response_class": {
+ "get": {
+ "summary": "No Response Model Annotation Json Response Class",
+ "operationId": "no_response_model_annotation_json_response_class_no_response_model_annotation_json_response_class_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ },
+ },
+ "User": {
+ "title": "User",
+ "required": ["name", "surname"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "surname": {"title": "Surname", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_response_model_sub_types.py b/tests/test_response_model_sub_types.py
index fd972e6a3..e462006ff 100644
--- a/tests/test_response_model_sub_types.py
+++ b/tests/test_response_model_sub_types.py
@@ -32,129 +32,127 @@ def valid4():
pass
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/valid1": {
- "get": {
- "summary": "Valid1",
- "operationId": "valid1_valid1_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "500": {
- "description": "Internal Server Error",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response 500 Valid1 Valid1 Get",
- "type": "integer",
+client = TestClient(app)
+
+
+def test_path_operations():
+ response = client.get("/valid1")
+ assert response.status_code == 200, response.text
+ response = client.get("/valid2")
+ assert response.status_code == 200, response.text
+ response = client.get("/valid3")
+ assert response.status_code == 200, response.text
+ response = client.get("/valid4")
+ assert response.status_code == 200, response.text
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/valid1": {
+ "get": {
+ "summary": "Valid1",
+ "operationId": "valid1_valid1_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 500 Valid1 Valid1 Get",
+ "type": "integer",
+ }
}
- }
+ },
},
},
- },
- }
- },
- "/valid2": {
- "get": {
- "summary": "Valid2",
- "operationId": "valid2_valid2_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "500": {
- "description": "Internal Server Error",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response 500 Valid2 Valid2 Get",
- "type": "array",
- "items": {"type": "integer"},
+ }
+ },
+ "/valid2": {
+ "get": {
+ "summary": "Valid2",
+ "operationId": "valid2_valid2_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 500 Valid2 Valid2 Get",
+ "type": "array",
+ "items": {"type": "integer"},
+ }
}
- }
+ },
},
},
- },
- }
- },
- "/valid3": {
- "get": {
- "summary": "Valid3",
- "operationId": "valid3_valid3_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "500": {
- "description": "Internal Server Error",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Model"}
- }
+ }
+ },
+ "/valid3": {
+ "get": {
+ "summary": "Valid3",
+ "operationId": "valid3_valid3_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Model"}
+ }
+ },
},
},
- },
- }
- },
- "/valid4": {
- "get": {
- "summary": "Valid4",
- "operationId": "valid4_valid4_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "500": {
- "description": "Internal Server Error",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response 500 Valid4 Valid4 Get",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Model"},
+ }
+ },
+ "/valid4": {
+ "get": {
+ "summary": "Valid4",
+ "operationId": "valid4_valid4_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response 500 Valid4 Valid4 Get",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Model"},
+ }
}
- }
+ },
},
},
- },
- }
+ }
+ },
},
- },
- "components": {
- "schemas": {
- "Model": {
- "title": "Model",
- "required": ["name"],
- "type": "object",
- "properties": {"name": {"title": "Name", "type": "string"}},
+ "components": {
+ "schemas": {
+ "Model": {
+ "title": "Model",
+ "required": ["name"],
+ "type": "object",
+ "properties": {"name": {"title": "Name", "type": "string"}},
+ }
}
- }
- },
-}
-
-client = TestClient(app)
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
-def test_path_operations():
- response = client.get("/valid1")
- assert response.status_code == 200, response.text
- response = client.get("/valid2")
- assert response.status_code == 200, response.text
- response = client.get("/valid3")
- assert response.status_code == 200, response.text
- response = client.get("/valid4")
- assert response.status_code == 200, response.text
+ },
+ }
diff --git a/tests/test_route_scope.py b/tests/test_route_scope.py
index a188e9a5f..2021c828f 100644
--- a/tests/test_route_scope.py
+++ b/tests/test_route_scope.py
@@ -46,5 +46,5 @@ def test_websocket():
def test_websocket_invalid_path_doesnt_match():
with pytest.raises(WebSocketDisconnect):
- with client.websocket_connect("/itemsx/portal-gun") as websocket:
- websocket.receive_json()
+ with client.websocket_connect("/itemsx/portal-gun"):
+ pass
diff --git a/tests/test_router_events.py b/tests/test_router_events.py
index 5ff1fdf9f..ba6b76382 100644
--- a/tests/test_router_events.py
+++ b/tests/test_router_events.py
@@ -1,3 +1,7 @@
+from contextlib import asynccontextmanager
+from typing import AsyncGenerator, Dict
+
+import pytest
from fastapi import APIRouter, FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel
@@ -12,57 +16,49 @@ class State(BaseModel):
sub_router_shutdown: bool = False
-state = State()
-
-app = FastAPI()
-
-
-@app.on_event("startup")
-def app_startup():
- state.app_startup = True
-
-
-@app.on_event("shutdown")
-def app_shutdown():
- state.app_shutdown = True
-
+@pytest.fixture
+def state() -> State:
+ return State()
-router = APIRouter()
+def test_router_events(state: State) -> None:
+ app = FastAPI()
-@router.on_event("startup")
-def router_startup():
- state.router_startup = True
+ @app.get("/")
+ def main() -> Dict[str, str]:
+ return {"message": "Hello World"}
+ @app.on_event("startup")
+ def app_startup() -> None:
+ state.app_startup = True
-@router.on_event("shutdown")
-def router_shutdown():
- state.router_shutdown = True
+ @app.on_event("shutdown")
+ def app_shutdown() -> None:
+ state.app_shutdown = True
+ router = APIRouter()
-sub_router = APIRouter()
+ @router.on_event("startup")
+ def router_startup() -> None:
+ state.router_startup = True
+ @router.on_event("shutdown")
+ def router_shutdown() -> None:
+ state.router_shutdown = True
-@sub_router.on_event("startup")
-def sub_router_startup():
- state.sub_router_startup = True
+ sub_router = APIRouter()
+ @sub_router.on_event("startup")
+ def sub_router_startup() -> None:
+ state.sub_router_startup = True
-@sub_router.on_event("shutdown")
-def sub_router_shutdown():
- state.sub_router_shutdown = True
+ @sub_router.on_event("shutdown")
+ def sub_router_shutdown() -> None:
+ state.sub_router_shutdown = True
+ router.include_router(sub_router)
+ app.include_router(router)
-@sub_router.get("/")
-def main():
- return {"message": "Hello World"}
-
-
-router.include_router(sub_router)
-app.include_router(router)
-
-
-def test_router_events():
assert state.app_startup is False
assert state.router_startup is False
assert state.sub_router_startup is False
@@ -85,3 +81,28 @@ def test_router_events():
assert state.app_shutdown is True
assert state.router_shutdown is True
assert state.sub_router_shutdown is True
+
+
+def test_app_lifespan_state(state: State) -> None:
+ @asynccontextmanager
+ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
+ state.app_startup = True
+ yield
+ state.app_shutdown = True
+
+ app = FastAPI(lifespan=lifespan)
+
+ @app.get("/")
+ def main() -> Dict[str, str]:
+ return {"message": "Hello World"}
+
+ assert state.app_startup is False
+ assert state.app_shutdown is False
+ with TestClient(app) as client:
+ assert state.app_startup is True
+ assert state.app_shutdown is False
+ response = client.get("/")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"message": "Hello World"}
+ assert state.app_startup is True
+ assert state.app_shutdown is True
diff --git a/tests/test_schema_extra_examples.py b/tests/test_schema_extra_examples.py
index f07d2c3b8..74e15d59a 100644
--- a/tests/test_schema_extra_examples.py
+++ b/tests/test_schema_extra_examples.py
@@ -234,653 +234,654 @@ def cookie_example_examples(
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/schema_extra/": {
- "post": {
- "summary": "Schema Extra",
- "operationId": "schema_extra_schema_extra__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
+def test_call_api():
+ response = client.post("/schema_extra/", json={"data": "Foo"})
+ assert response.status_code == 200, response.text
+ response = client.post("/example/", json={"data": "Foo"})
+ assert response.status_code == 200, response.text
+ response = client.post("/examples/", json={"data": "Foo"})
+ assert response.status_code == 200, response.text
+ response = client.post("/example_examples/", json={"data": "Foo"})
+ assert response.status_code == 200, response.text
+ response = client.get("/path_example/foo")
+ assert response.status_code == 200, response.text
+ response = client.get("/path_examples/foo")
+ assert response.status_code == 200, response.text
+ response = client.get("/path_example_examples/foo")
+ assert response.status_code == 200, response.text
+ response = client.get("/query_example/")
+ assert response.status_code == 200, response.text
+ response = client.get("/query_examples/")
+ assert response.status_code == 200, response.text
+ response = client.get("/query_example_examples/")
+ assert response.status_code == 200, response.text
+ response = client.get("/header_example/")
+ assert response.status_code == 200, response.text
+ response = client.get("/header_examples/")
+ assert response.status_code == 200, response.text
+ response = client.get("/header_example_examples/")
+ assert response.status_code == 200, response.text
+ response = client.get("/cookie_example/")
+ assert response.status_code == 200, response.text
+ response = client.get("/cookie_examples/")
+ assert response.status_code == 200, response.text
+ response = client.get("/cookie_example_examples/")
+ assert response.status_code == 200, response.text
+
+
+def test_openapi_schema():
+ """
+ Test that example overrides work:
+
+ * pydantic model schema_extra is included
+ * Body(example={}) overrides schema_extra in pydantic model
+ * Body(examples{}) overrides Body(example={}) and schema_extra in pydantic model
+ """
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/schema_extra/": {
+ "post": {
+ "summary": "Schema Extra",
+ "operationId": "schema_extra_schema_extra__post",
+ "requestBody": {
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
+ "required": True,
},
- },
- }
- },
- "/example/": {
- "post": {
- "summary": "Example",
- "operationId": "example_example__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"},
- "example": {"data": "Data in Body example"},
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- "422": {
- "description": "Validation Error",
+ }
+ },
+ "/example/": {
+ "post": {
+ "summary": "Example",
+ "operationId": "example_example__post",
+ "requestBody": {
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
+ "schema": {"$ref": "#/components/schemas/Item"},
+ "example": {"data": "Data in Body example"},
}
},
+ "required": True,
},
- },
- }
- },
- "/examples/": {
- "post": {
- "summary": "Examples",
- "operationId": "examples_examples__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"},
- "examples": {
- "example1": {
- "summary": "example1 summary",
- "value": {
- "data": "Data in Body examples, example1"
- },
- },
- "example2": {
- "value": {"data": "Data in Body examples, example2"}
- },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
},
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ },
},
- "422": {
- "description": "Validation Error",
+ }
+ },
+ "/examples/": {
+ "post": {
+ "summary": "Examples",
+ "operationId": "examples_examples__post",
+ "requestBody": {
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
+ "schema": {"$ref": "#/components/schemas/Item"},
+ "examples": {
+ "example1": {
+ "summary": "example1 summary",
+ "value": {
+ "data": "Data in Body examples, example1"
+ },
+ },
+ "example2": {
+ "value": {
+ "data": "Data in Body examples, example2"
+ }
+ },
+ },
}
},
+ "required": True,
},
- },
- }
- },
- "/example_examples/": {
- "post": {
- "summary": "Example Examples",
- "operationId": "example_examples_example_examples__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"},
- "examples": {
- "example1": {
- "value": {"data": "examples example_examples 1"}
- },
- "example2": {
- "value": {"data": "examples example_examples 2"}
- },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
},
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ },
},
- "422": {
- "description": "Validation Error",
+ }
+ },
+ "/example_examples/": {
+ "post": {
+ "summary": "Example Examples",
+ "operationId": "example_examples_example_examples__post",
+ "requestBody": {
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
+ "schema": {"$ref": "#/components/schemas/Item"},
+ "examples": {
+ "example1": {
+ "value": {"data": "examples example_examples 1"}
+ },
+ "example2": {
+ "value": {"data": "examples example_examples 2"}
+ },
+ },
}
},
- },
- },
- }
- },
- "/path_example/{item_id}": {
- "get": {
- "summary": "Path Example",
- "operationId": "path_example_path_example__item_id__get",
- "parameters": [
- {
"required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "example": "item_1",
- "name": "item_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- }
- },
- "/path_examples/{item_id}": {
- "get": {
- "summary": "Path Examples",
- "operationId": "path_examples_path_examples__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "examples": {
- "example1": {
- "summary": "item ID summary",
- "value": "item_1",
+ }
+ },
+ "/path_example/{item_id}": {
+ "get": {
+ "summary": "Path Example",
+ "operationId": "path_example_path_example__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "example": "item_1",
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
},
- "example2": {"value": "item_2"},
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
+ },
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ },
+ "/path_examples/{item_id}": {
+ "get": {
+ "summary": "Path Examples",
+ "operationId": "path_examples_path_examples__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "examples": {
+ "example1": {
+ "summary": "item ID summary",
+ "value": "item_1",
+ },
+ "example2": {"value": "item_2"},
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- }
- },
- "/path_example_examples/{item_id}": {
- "get": {
- "summary": "Path Example Examples",
- "operationId": "path_example_examples_path_example_examples__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "examples": {
- "example1": {
- "summary": "item ID summary",
- "value": "item_1",
+ }
+ },
+ "/path_example_examples/{item_id}": {
+ "get": {
+ "summary": "Path Example Examples",
+ "operationId": "path_example_examples_path_example_examples__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "examples": {
+ "example1": {
+ "summary": "item ID summary",
+ "value": "item_1",
+ },
+ "example2": {"value": "item_2"},
},
- "example2": {"value": "item_2"},
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- }
- },
- "/query_example/": {
- "get": {
- "summary": "Query Example",
- "operationId": "query_example_query_example__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Data", "type": "string"},
- "example": "query1",
- "name": "data",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ },
+ "/query_example/": {
+ "get": {
+ "summary": "Query Example",
+ "operationId": "query_example_query_example__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Data", "type": "string"},
+ "example": "query1",
+ "name": "data",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- }
- },
- "/query_examples/": {
- "get": {
- "summary": "Query Examples",
- "operationId": "query_examples_query_examples__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Data", "type": "string"},
- "examples": {
- "example1": {
- "summary": "Query example 1",
- "value": "query1",
+ }
+ },
+ "/query_examples/": {
+ "get": {
+ "summary": "Query Examples",
+ "operationId": "query_examples_query_examples__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Data", "type": "string"},
+ "examples": {
+ "example1": {
+ "summary": "Query example 1",
+ "value": "query1",
+ },
+ "example2": {"value": "query2"},
},
- "example2": {"value": "query2"},
- },
- "name": "data",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "name": "data",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- }
- },
- "/query_example_examples/": {
- "get": {
- "summary": "Query Example Examples",
- "operationId": "query_example_examples_query_example_examples__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Data", "type": "string"},
- "examples": {
- "example1": {
- "summary": "Query example 1",
- "value": "query1",
+ }
+ },
+ "/query_example_examples/": {
+ "get": {
+ "summary": "Query Example Examples",
+ "operationId": "query_example_examples_query_example_examples__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Data", "type": "string"},
+ "examples": {
+ "example1": {
+ "summary": "Query example 1",
+ "value": "query1",
+ },
+ "example2": {"value": "query2"},
},
- "example2": {"value": "query2"},
- },
- "name": "data",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "name": "data",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- }
- },
- "/header_example/": {
- "get": {
- "summary": "Header Example",
- "operationId": "header_example_header_example__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Data", "type": "string"},
- "example": "header1",
- "name": "data",
- "in": "header",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ },
+ "/header_example/": {
+ "get": {
+ "summary": "Header Example",
+ "operationId": "header_example_header_example__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Data", "type": "string"},
+ "example": "header1",
+ "name": "data",
+ "in": "header",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- }
- },
- "/header_examples/": {
- "get": {
- "summary": "Header Examples",
- "operationId": "header_examples_header_examples__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Data", "type": "string"},
- "examples": {
- "example1": {
- "summary": "header example 1",
- "value": "header1",
+ }
+ },
+ "/header_examples/": {
+ "get": {
+ "summary": "Header Examples",
+ "operationId": "header_examples_header_examples__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Data", "type": "string"},
+ "examples": {
+ "example1": {
+ "summary": "header example 1",
+ "value": "header1",
+ },
+ "example2": {"value": "header2"},
},
- "example2": {"value": "header2"},
- },
- "name": "data",
- "in": "header",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "name": "data",
+ "in": "header",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- }
- },
- "/header_example_examples/": {
- "get": {
- "summary": "Header Example Examples",
- "operationId": "header_example_examples_header_example_examples__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Data", "type": "string"},
- "examples": {
- "example1": {
- "summary": "Query example 1",
- "value": "header1",
+ }
+ },
+ "/header_example_examples/": {
+ "get": {
+ "summary": "Header Example Examples",
+ "operationId": "header_example_examples_header_example_examples__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Data", "type": "string"},
+ "examples": {
+ "example1": {
+ "summary": "Query example 1",
+ "value": "header1",
+ },
+ "example2": {"value": "header2"},
},
- "example2": {"value": "header2"},
- },
- "name": "data",
- "in": "header",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "name": "data",
+ "in": "header",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- }
- },
- "/cookie_example/": {
- "get": {
- "summary": "Cookie Example",
- "operationId": "cookie_example_cookie_example__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Data", "type": "string"},
- "example": "cookie1",
- "name": "data",
- "in": "cookie",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ },
+ "/cookie_example/": {
+ "get": {
+ "summary": "Cookie Example",
+ "operationId": "cookie_example_cookie_example__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Data", "type": "string"},
+ "example": "cookie1",
+ "name": "data",
+ "in": "cookie",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- }
- },
- "/cookie_examples/": {
- "get": {
- "summary": "Cookie Examples",
- "operationId": "cookie_examples_cookie_examples__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Data", "type": "string"},
- "examples": {
- "example1": {
- "summary": "cookie example 1",
- "value": "cookie1",
+ }
+ },
+ "/cookie_examples/": {
+ "get": {
+ "summary": "Cookie Examples",
+ "operationId": "cookie_examples_cookie_examples__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Data", "type": "string"},
+ "examples": {
+ "example1": {
+ "summary": "cookie example 1",
+ "value": "cookie1",
+ },
+ "example2": {"value": "cookie2"},
},
- "example2": {"value": "cookie2"},
- },
- "name": "data",
- "in": "cookie",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "name": "data",
+ "in": "cookie",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- }
- },
- "/cookie_example_examples/": {
- "get": {
- "summary": "Cookie Example Examples",
- "operationId": "cookie_example_examples_cookie_example_examples__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Data", "type": "string"},
- "examples": {
- "example1": {
- "summary": "Query example 1",
- "value": "cookie1",
+ }
+ },
+ "/cookie_example_examples/": {
+ "get": {
+ "summary": "Cookie Example Examples",
+ "operationId": "cookie_example_examples_cookie_example_examples__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Data", "type": "string"},
+ "examples": {
+ "example1": {
+ "summary": "Query example 1",
+ "value": "cookie1",
+ },
+ "example2": {"value": "cookie2"},
},
- "example2": {"value": "cookie2"},
- },
- "name": "data",
- "in": "cookie",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "name": "data",
+ "in": "cookie",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
}
- }
+ },
},
},
- },
- }
+ }
+ },
},
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
},
- },
- "Item": {
- "title": "Item",
- "required": ["data"],
- "type": "object",
- "properties": {"data": {"title": "Data", "type": "string"}},
- "example": {"data": "Data in schema_extra"},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ "Item": {
+ "title": "Item",
+ "required": ["data"],
+ "type": "object",
+ "properties": {"data": {"title": "Data", "type": "string"}},
+ "example": {"data": "Data in schema_extra"},
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
},
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
},
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- """
- Test that example overrides work:
-
- * pydantic model schema_extra is included
- * Body(example={}) overrides schema_extra in pydantic model
- * Body(examples{}) overrides Body(example={}) and schema_extra in pydantic model
- """
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
-def test_call_api():
- response = client.post("/schema_extra/", json={"data": "Foo"})
- assert response.status_code == 200, response.text
- response = client.post("/example/", json={"data": "Foo"})
- assert response.status_code == 200, response.text
- response = client.post("/examples/", json={"data": "Foo"})
- assert response.status_code == 200, response.text
- response = client.post("/example_examples/", json={"data": "Foo"})
- assert response.status_code == 200, response.text
- response = client.get("/path_example/foo")
- assert response.status_code == 200, response.text
- response = client.get("/path_examples/foo")
- assert response.status_code == 200, response.text
- response = client.get("/path_example_examples/foo")
- assert response.status_code == 200, response.text
- response = client.get("/query_example/")
- assert response.status_code == 200, response.text
- response = client.get("/query_examples/")
- assert response.status_code == 200, response.text
- response = client.get("/query_example_examples/")
- assert response.status_code == 200, response.text
- response = client.get("/header_example/")
- assert response.status_code == 200, response.text
- response = client.get("/header_examples/")
- assert response.status_code == 200, response.text
- response = client.get("/header_example_examples/")
- assert response.status_code == 200, response.text
- response = client.get("/cookie_example/")
- assert response.status_code == 200, response.text
- response = client.get("/cookie_examples/")
- assert response.status_code == 200, response.text
- response = client.get("/cookie_example_examples/")
- assert response.status_code == 200, response.text
+ }
+ },
+ }
diff --git a/tests/test_security_api_key_cookie.py b/tests/test_security_api_key_cookie.py
index 0bf4e9bb3..b1c648c55 100644
--- a/tests/test_security_api_key_cookie.py
+++ b/tests/test_security_api_key_cookie.py
@@ -22,39 +22,6 @@ def read_current_user(current_user: User = Depends(get_current_user)):
return current_user
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"APIKeyCookie": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "APIKeyCookie": {"type": "apiKey", "name": "key", "in": "cookie"}
- }
- },
-}
-
-
-def test_openapi_schema():
- client = TestClient(app)
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
def test_security_api_key():
client = TestClient(app, cookies={"key": "secret"})
response = client.get("/users/me")
@@ -67,3 +34,33 @@ def test_security_api_key_no_key():
response = client.get("/users/me")
assert response.status_code == 403, response.text
assert response.json() == {"detail": "Not authenticated"}
+
+
+def test_openapi_schema():
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"APIKeyCookie": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "APIKeyCookie": {"type": "apiKey", "name": "key", "in": "cookie"}
+ }
+ },
+ }
diff --git a/tests/test_security_api_key_cookie_description.py b/tests/test_security_api_key_cookie_description.py
index ed4e65239..ac8b4abf8 100644
--- a/tests/test_security_api_key_cookie_description.py
+++ b/tests/test_security_api_key_cookie_description.py
@@ -22,44 +22,6 @@ def read_current_user(current_user: User = Depends(get_current_user)):
return current_user
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"APIKeyCookie": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "APIKeyCookie": {
- "type": "apiKey",
- "name": "key",
- "in": "cookie",
- "description": "An API Cookie Key",
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- client = TestClient(app)
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
def test_security_api_key():
client = TestClient(app, cookies={"key": "secret"})
response = client.get("/users/me")
@@ -72,3 +34,38 @@ def test_security_api_key_no_key():
response = client.get("/users/me")
assert response.status_code == 403, response.text
assert response.json() == {"detail": "Not authenticated"}
+
+
+def test_openapi_schema():
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"APIKeyCookie": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "APIKeyCookie": {
+ "type": "apiKey",
+ "name": "key",
+ "in": "cookie",
+ "description": "An API Cookie Key",
+ }
+ }
+ },
+ }
diff --git a/tests/test_security_api_key_cookie_optional.py b/tests/test_security_api_key_cookie_optional.py
index 3e7aa81c0..b8c440c9d 100644
--- a/tests/test_security_api_key_cookie_optional.py
+++ b/tests/test_security_api_key_cookie_optional.py
@@ -29,39 +29,6 @@ def read_current_user(current_user: User = Depends(get_current_user)):
return current_user
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"APIKeyCookie": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "APIKeyCookie": {"type": "apiKey", "name": "key", "in": "cookie"}
- }
- },
-}
-
-
-def test_openapi_schema():
- client = TestClient(app)
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
def test_security_api_key():
client = TestClient(app, cookies={"key": "secret"})
response = client.get("/users/me")
@@ -74,3 +41,33 @@ def test_security_api_key_no_key():
response = client.get("/users/me")
assert response.status_code == 200, response.text
assert response.json() == {"msg": "Create an account first"}
+
+
+def test_openapi_schema():
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"APIKeyCookie": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "APIKeyCookie": {"type": "apiKey", "name": "key", "in": "cookie"}
+ }
+ },
+ }
diff --git a/tests/test_security_api_key_header.py b/tests/test_security_api_key_header.py
index d53395f99..96ad80b54 100644
--- a/tests/test_security_api_key_header.py
+++ b/tests/test_security_api_key_header.py
@@ -24,37 +24,6 @@ def read_current_user(current_user: User = Depends(get_current_user)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"APIKeyHeader": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "APIKeyHeader": {"type": "apiKey", "name": "key", "in": "header"}
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_api_key():
response = client.get("/users/me", headers={"key": "secret"})
@@ -66,3 +35,32 @@ def test_security_api_key_no_key():
response = client.get("/users/me")
assert response.status_code == 403, response.text
assert response.json() == {"detail": "Not authenticated"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"APIKeyHeader": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "APIKeyHeader": {"type": "apiKey", "name": "key", "in": "header"}
+ }
+ },
+ }
diff --git a/tests/test_security_api_key_header_description.py b/tests/test_security_api_key_header_description.py
index cc9802708..382f53dd7 100644
--- a/tests/test_security_api_key_header_description.py
+++ b/tests/test_security_api_key_header_description.py
@@ -24,42 +24,6 @@ def read_current_user(current_user: User = Depends(get_current_user)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"APIKeyHeader": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "APIKeyHeader": {
- "type": "apiKey",
- "name": "key",
- "in": "header",
- "description": "An API Key Header",
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_api_key():
response = client.get("/users/me", headers={"key": "secret"})
@@ -71,3 +35,37 @@ def test_security_api_key_no_key():
response = client.get("/users/me")
assert response.status_code == 403, response.text
assert response.json() == {"detail": "Not authenticated"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"APIKeyHeader": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "APIKeyHeader": {
+ "type": "apiKey",
+ "name": "key",
+ "in": "header",
+ "description": "An API Key Header",
+ }
+ }
+ },
+ }
diff --git a/tests/test_security_api_key_header_optional.py b/tests/test_security_api_key_header_optional.py
index 4ab599c2d..adfb20ba0 100644
--- a/tests/test_security_api_key_header_optional.py
+++ b/tests/test_security_api_key_header_optional.py
@@ -30,37 +30,6 @@ def read_current_user(current_user: Optional[User] = Depends(get_current_user)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"APIKeyHeader": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "APIKeyHeader": {"type": "apiKey", "name": "key", "in": "header"}
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_api_key():
response = client.get("/users/me", headers={"key": "secret"})
@@ -72,3 +41,32 @@ def test_security_api_key_no_key():
response = client.get("/users/me")
assert response.status_code == 200, response.text
assert response.json() == {"msg": "Create an account first"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"APIKeyHeader": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "APIKeyHeader": {"type": "apiKey", "name": "key", "in": "header"}
+ }
+ },
+ }
diff --git a/tests/test_security_api_key_query.py b/tests/test_security_api_key_query.py
index 4844c65e2..da98eafd6 100644
--- a/tests/test_security_api_key_query.py
+++ b/tests/test_security_api_key_query.py
@@ -24,37 +24,6 @@ def read_current_user(current_user: User = Depends(get_current_user)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"APIKeyQuery": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "APIKeyQuery": {"type": "apiKey", "name": "key", "in": "query"}
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_api_key():
response = client.get("/users/me?key=secret")
@@ -66,3 +35,32 @@ def test_security_api_key_no_key():
response = client.get("/users/me")
assert response.status_code == 403, response.text
assert response.json() == {"detail": "Not authenticated"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"APIKeyQuery": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "APIKeyQuery": {"type": "apiKey", "name": "key", "in": "query"}
+ }
+ },
+ }
diff --git a/tests/test_security_api_key_query_description.py b/tests/test_security_api_key_query_description.py
index 9b608233a..3c08afc5f 100644
--- a/tests/test_security_api_key_query_description.py
+++ b/tests/test_security_api_key_query_description.py
@@ -24,42 +24,6 @@ def read_current_user(current_user: User = Depends(get_current_user)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"APIKeyQuery": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "APIKeyQuery": {
- "type": "apiKey",
- "name": "key",
- "in": "query",
- "description": "API Key Query",
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_api_key():
response = client.get("/users/me?key=secret")
@@ -71,3 +35,37 @@ def test_security_api_key_no_key():
response = client.get("/users/me")
assert response.status_code == 403, response.text
assert response.json() == {"detail": "Not authenticated"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"APIKeyQuery": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "APIKeyQuery": {
+ "type": "apiKey",
+ "name": "key",
+ "in": "query",
+ "description": "API Key Query",
+ }
+ }
+ },
+ }
diff --git a/tests/test_security_api_key_query_optional.py b/tests/test_security_api_key_query_optional.py
index 9339b7b3a..99a26cfd0 100644
--- a/tests/test_security_api_key_query_optional.py
+++ b/tests/test_security_api_key_query_optional.py
@@ -30,37 +30,6 @@ def read_current_user(current_user: Optional[User] = Depends(get_current_user)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"APIKeyQuery": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "APIKeyQuery": {"type": "apiKey", "name": "key", "in": "query"}
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_api_key():
response = client.get("/users/me?key=secret")
@@ -72,3 +41,32 @@ def test_security_api_key_no_key():
response = client.get("/users/me")
assert response.status_code == 200, response.text
assert response.json() == {"msg": "Create an account first"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"APIKeyQuery": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "APIKeyQuery": {"type": "apiKey", "name": "key", "in": "query"}
+ }
+ },
+ }
diff --git a/tests/test_security_http_base.py b/tests/test_security_http_base.py
index 894716279..d3a754203 100644
--- a/tests/test_security_http_base.py
+++ b/tests/test_security_http_base.py
@@ -14,35 +14,6 @@ def read_current_user(credentials: HTTPAuthorizationCredentials = Security(secur
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"HTTPBase": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {"HTTPBase": {"type": "http", "scheme": "Other"}}
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_http_base():
response = client.get("/users/me", headers={"Authorization": "Other foobar"})
@@ -54,3 +25,30 @@ def test_security_http_base_no_credentials():
response = client.get("/users/me")
assert response.status_code == 403, response.text
assert response.json() == {"detail": "Not authenticated"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"HTTPBase": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {"HTTPBase": {"type": "http", "scheme": "Other"}}
+ },
+ }
diff --git a/tests/test_security_http_base_description.py b/tests/test_security_http_base_description.py
index 5855e8df4..3d7d15016 100644
--- a/tests/test_security_http_base_description.py
+++ b/tests/test_security_http_base_description.py
@@ -14,41 +14,6 @@ def read_current_user(credentials: HTTPAuthorizationCredentials = Security(secur
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"HTTPBase": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "HTTPBase": {
- "type": "http",
- "scheme": "Other",
- "description": "Other Security Scheme",
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_http_base():
response = client.get("/users/me", headers={"Authorization": "Other foobar"})
@@ -60,3 +25,36 @@ def test_security_http_base_no_credentials():
response = client.get("/users/me")
assert response.status_code == 403, response.text
assert response.json() == {"detail": "Not authenticated"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"HTTPBase": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "HTTPBase": {
+ "type": "http",
+ "scheme": "Other",
+ "description": "Other Security Scheme",
+ }
+ }
+ },
+ }
diff --git a/tests/test_security_http_base_optional.py b/tests/test_security_http_base_optional.py
index 5a50f9b88..180c9110e 100644
--- a/tests/test_security_http_base_optional.py
+++ b/tests/test_security_http_base_optional.py
@@ -20,35 +20,6 @@ def read_current_user(
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"HTTPBase": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {"HTTPBase": {"type": "http", "scheme": "Other"}}
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_http_base():
response = client.get("/users/me", headers={"Authorization": "Other foobar"})
@@ -60,3 +31,30 @@ def test_security_http_base_no_credentials():
response = client.get("/users/me")
assert response.status_code == 200, response.text
assert response.json() == {"msg": "Create an account first"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"HTTPBase": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {"HTTPBase": {"type": "http", "scheme": "Other"}}
+ },
+ }
diff --git a/tests/test_security_http_basic_optional.py b/tests/test_security_http_basic_optional.py
index 91824d223..7e7fcac32 100644
--- a/tests/test_security_http_basic_optional.py
+++ b/tests/test_security_http_basic_optional.py
@@ -19,35 +19,6 @@ def read_current_user(credentials: Optional[HTTPBasicCredentials] = Security(sec
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"HTTPBasic": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {"HTTPBasic": {"type": "http", "scheme": "basic"}}
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_http_basic():
response = client.get("/users/me", auth=("john", "secret"))
@@ -77,3 +48,30 @@ def test_security_http_basic_non_basic_credentials():
assert response.status_code == 401, response.text
assert response.headers["WWW-Authenticate"] == "Basic"
assert response.json() == {"detail": "Invalid authentication credentials"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"HTTPBasic": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {"HTTPBasic": {"type": "http", "scheme": "basic"}}
+ },
+ }
diff --git a/tests/test_security_http_basic_realm.py b/tests/test_security_http_basic_realm.py
index 6d760c0f9..470afd662 100644
--- a/tests/test_security_http_basic_realm.py
+++ b/tests/test_security_http_basic_realm.py
@@ -16,35 +16,6 @@ def read_current_user(credentials: HTTPBasicCredentials = Security(security)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"HTTPBasic": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {"HTTPBasic": {"type": "http", "scheme": "basic"}}
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_http_basic():
response = client.get("/users/me", auth=("john", "secret"))
@@ -75,3 +46,30 @@ def test_security_http_basic_non_basic_credentials():
assert response.status_code == 401, response.text
assert response.headers["WWW-Authenticate"] == 'Basic realm="simple"'
assert response.json() == {"detail": "Invalid authentication credentials"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"HTTPBasic": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {"HTTPBasic": {"type": "http", "scheme": "basic"}}
+ },
+ }
diff --git a/tests/test_security_http_basic_realm_description.py b/tests/test_security_http_basic_realm_description.py
index 7cc547561..44289007b 100644
--- a/tests/test_security_http_basic_realm_description.py
+++ b/tests/test_security_http_basic_realm_description.py
@@ -16,41 +16,6 @@ def read_current_user(credentials: HTTPBasicCredentials = Security(security)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"HTTPBasic": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "HTTPBasic": {
- "type": "http",
- "scheme": "basic",
- "description": "HTTPBasic scheme",
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_http_basic():
response = client.get("/users/me", auth=("john", "secret"))
@@ -81,3 +46,36 @@ def test_security_http_basic_non_basic_credentials():
assert response.status_code == 401, response.text
assert response.headers["WWW-Authenticate"] == 'Basic realm="simple"'
assert response.json() == {"detail": "Invalid authentication credentials"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"HTTPBasic": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "HTTPBasic": {
+ "type": "http",
+ "scheme": "basic",
+ "description": "HTTPBasic scheme",
+ }
+ }
+ },
+ }
diff --git a/tests/test_security_http_bearer.py b/tests/test_security_http_bearer.py
index 39d8c8402..f24869fc3 100644
--- a/tests/test_security_http_bearer.py
+++ b/tests/test_security_http_bearer.py
@@ -14,35 +14,6 @@ def read_current_user(credentials: HTTPAuthorizationCredentials = Security(secur
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"HTTPBearer": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {"HTTPBearer": {"type": "http", "scheme": "bearer"}}
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_http_bearer():
response = client.get("/users/me", headers={"Authorization": "Bearer foobar"})
@@ -60,3 +31,30 @@ def test_security_http_bearer_incorrect_scheme_credentials():
response = client.get("/users/me", headers={"Authorization": "Basic notreally"})
assert response.status_code == 403, response.text
assert response.json() == {"detail": "Invalid authentication credentials"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"HTTPBearer": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {"HTTPBearer": {"type": "http", "scheme": "bearer"}}
+ },
+ }
diff --git a/tests/test_security_http_bearer_description.py b/tests/test_security_http_bearer_description.py
index 132e720fc..6d5ad0b8e 100644
--- a/tests/test_security_http_bearer_description.py
+++ b/tests/test_security_http_bearer_description.py
@@ -14,41 +14,6 @@ def read_current_user(credentials: HTTPAuthorizationCredentials = Security(secur
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"HTTPBearer": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "HTTPBearer": {
- "type": "http",
- "scheme": "bearer",
- "description": "HTTP Bearer token scheme",
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_http_bearer():
response = client.get("/users/me", headers={"Authorization": "Bearer foobar"})
@@ -66,3 +31,36 @@ def test_security_http_bearer_incorrect_scheme_credentials():
response = client.get("/users/me", headers={"Authorization": "Basic notreally"})
assert response.status_code == 403, response.text
assert response.json() == {"detail": "Invalid authentication credentials"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"HTTPBearer": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "HTTPBearer": {
+ "type": "http",
+ "scheme": "bearer",
+ "description": "HTTP Bearer token scheme",
+ }
+ }
+ },
+ }
diff --git a/tests/test_security_http_bearer_optional.py b/tests/test_security_http_bearer_optional.py
index 2e7dfb8a4..b596ac730 100644
--- a/tests/test_security_http_bearer_optional.py
+++ b/tests/test_security_http_bearer_optional.py
@@ -20,35 +20,6 @@ def read_current_user(
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"HTTPBearer": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {"HTTPBearer": {"type": "http", "scheme": "bearer"}}
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_http_bearer():
response = client.get("/users/me", headers={"Authorization": "Bearer foobar"})
@@ -66,3 +37,30 @@ def test_security_http_bearer_incorrect_scheme_credentials():
response = client.get("/users/me", headers={"Authorization": "Basic notreally"})
assert response.status_code == 200, response.text
assert response.json() == {"msg": "Create an account first"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"HTTPBearer": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {"HTTPBearer": {"type": "http", "scheme": "bearer"}}
+ },
+ }
diff --git a/tests/test_security_http_digest.py b/tests/test_security_http_digest.py
index 8388824ff..2a25efe02 100644
--- a/tests/test_security_http_digest.py
+++ b/tests/test_security_http_digest.py
@@ -14,35 +14,6 @@ def read_current_user(credentials: HTTPAuthorizationCredentials = Security(secur
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"HTTPDigest": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {"HTTPDigest": {"type": "http", "scheme": "digest"}}
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_http_digest():
response = client.get("/users/me", headers={"Authorization": "Digest foobar"})
@@ -62,3 +33,30 @@ def test_security_http_digest_incorrect_scheme_credentials():
)
assert response.status_code == 403, response.text
assert response.json() == {"detail": "Invalid authentication credentials"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"HTTPDigest": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {"HTTPDigest": {"type": "http", "scheme": "digest"}}
+ },
+ }
diff --git a/tests/test_security_http_digest_description.py b/tests/test_security_http_digest_description.py
index d00aa1b6e..721f7cfde 100644
--- a/tests/test_security_http_digest_description.py
+++ b/tests/test_security_http_digest_description.py
@@ -14,41 +14,6 @@ def read_current_user(credentials: HTTPAuthorizationCredentials = Security(secur
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"HTTPDigest": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "HTTPDigest": {
- "type": "http",
- "scheme": "digest",
- "description": "HTTPDigest scheme",
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_http_digest():
response = client.get("/users/me", headers={"Authorization": "Digest foobar"})
@@ -68,3 +33,36 @@ def test_security_http_digest_incorrect_scheme_credentials():
)
assert response.status_code == 403, response.text
assert response.json() == {"detail": "Invalid authentication credentials"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"HTTPDigest": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "HTTPDigest": {
+ "type": "http",
+ "scheme": "digest",
+ "description": "HTTPDigest scheme",
+ }
+ }
+ },
+ }
diff --git a/tests/test_security_http_digest_optional.py b/tests/test_security_http_digest_optional.py
index 2177b819f..d4c3597bc 100644
--- a/tests/test_security_http_digest_optional.py
+++ b/tests/test_security_http_digest_optional.py
@@ -20,35 +20,6 @@ def read_current_user(
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"HTTPDigest": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {"HTTPDigest": {"type": "http", "scheme": "digest"}}
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_http_digest():
response = client.get("/users/me", headers={"Authorization": "Digest foobar"})
@@ -68,3 +39,30 @@ def test_security_http_digest_incorrect_scheme_credentials():
)
assert response.status_code == 403, response.text
assert response.json() == {"detail": "Invalid authentication credentials"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"HTTPDigest": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {"HTTPDigest": {"type": "http", "scheme": "digest"}}
+ },
+ }
diff --git a/tests/test_security_oauth2.py b/tests/test_security_oauth2.py
index b9ac488ee..23dce7cfa 100644
--- a/tests/test_security_oauth2.py
+++ b/tests/test_security_oauth2.py
@@ -40,124 +40,6 @@ def read_current_user(current_user: "User" = Depends(get_current_user)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/login": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Login",
- "operationId": "login_login_post",
- "requestBody": {
- "content": {
- "application/x-www-form-urlencoded": {
- "schema": {
- "$ref": "#/components/schemas/Body_login_login_post"
- }
- }
- },
- "required": True,
- },
- }
- },
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"OAuth2": []}],
- }
- },
- },
- "components": {
- "schemas": {
- "Body_login_login_post": {
- "title": "Body_login_login_post",
- "required": ["grant_type", "username", "password"],
- "type": "object",
- "properties": {
- "grant_type": {
- "title": "Grant Type",
- "pattern": "password",
- "type": "string",
- },
- "username": {"title": "Username", "type": "string"},
- "password": {"title": "Password", "type": "string"},
- "scope": {"title": "Scope", "type": "string", "default": ""},
- "client_id": {"title": "Client Id", "type": "string"},
- "client_secret": {"title": "Client Secret", "type": "string"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- },
- "securitySchemes": {
- "OAuth2": {
- "type": "oauth2",
- "flows": {
- "password": {
- "scopes": {
- "read:users": "Read the users",
- "write:users": "Create users",
- },
- "tokenUrl": "token",
- }
- },
- }
- },
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_oauth2():
response = client.get("/users/me", headers={"Authorization": "Bearer footokenbar"})
@@ -247,3 +129,121 @@ def test_strict_login(data, expected_status, expected_response):
response = client.post("/login", data=data)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/login": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Login",
+ "operationId": "login_login_post",
+ "requestBody": {
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_login_login_post"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ },
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"OAuth2": []}],
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_login_login_post": {
+ "title": "Body_login_login_post",
+ "required": ["grant_type", "username", "password"],
+ "type": "object",
+ "properties": {
+ "grant_type": {
+ "title": "Grant Type",
+ "pattern": "password",
+ "type": "string",
+ },
+ "username": {"title": "Username", "type": "string"},
+ "password": {"title": "Password", "type": "string"},
+ "scope": {"title": "Scope", "type": "string", "default": ""},
+ "client_id": {"title": "Client Id", "type": "string"},
+ "client_secret": {"title": "Client Secret", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ },
+ "securitySchemes": {
+ "OAuth2": {
+ "type": "oauth2",
+ "flows": {
+ "password": {
+ "scopes": {
+ "read:users": "Read the users",
+ "write:users": "Create users",
+ },
+ "tokenUrl": "token",
+ }
+ },
+ }
+ },
+ },
+ }
diff --git a/tests/test_security_oauth2_authorization_code_bearer.py b/tests/test_security_oauth2_authorization_code_bearer.py
index ad9a39ded..6df81528d 100644
--- a/tests/test_security_oauth2_authorization_code_bearer.py
+++ b/tests/test_security_oauth2_authorization_code_bearer.py
@@ -18,46 +18,6 @@ async def read_items(token: Optional[str] = Security(oauth2_scheme)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "security": [{"OAuth2AuthorizationCodeBearer": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "OAuth2AuthorizationCodeBearer": {
- "type": "oauth2",
- "flows": {
- "authorizationCode": {
- "authorizationUrl": "authorize",
- "tokenUrl": "token",
- "scopes": {},
- }
- },
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_no_token():
response = client.get("/items")
@@ -75,3 +35,41 @@ def test_token():
response = client.get("/items", headers={"Authorization": "Bearer testtoken"})
assert response.status_code == 200, response.text
assert response.json() == {"token": "testtoken"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "security": [{"OAuth2AuthorizationCodeBearer": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "OAuth2AuthorizationCodeBearer": {
+ "type": "oauth2",
+ "flows": {
+ "authorizationCode": {
+ "authorizationUrl": "authorize",
+ "tokenUrl": "token",
+ "scopes": {},
+ }
+ },
+ }
+ }
+ },
+ }
diff --git a/tests/test_security_oauth2_authorization_code_bearer_description.py b/tests/test_security_oauth2_authorization_code_bearer_description.py
index bdaa543fc..c119abde4 100644
--- a/tests/test_security_oauth2_authorization_code_bearer_description.py
+++ b/tests/test_security_oauth2_authorization_code_bearer_description.py
@@ -21,47 +21,6 @@ async def read_items(token: Optional[str] = Security(oauth2_scheme)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "security": [{"OAuth2AuthorizationCodeBearer": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "OAuth2AuthorizationCodeBearer": {
- "type": "oauth2",
- "flows": {
- "authorizationCode": {
- "authorizationUrl": "authorize",
- "tokenUrl": "token",
- "scopes": {},
- }
- },
- "description": "OAuth2 Code Bearer",
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_no_token():
response = client.get("/items")
@@ -79,3 +38,42 @@ def test_token():
response = client.get("/items", headers={"Authorization": "Bearer testtoken"})
assert response.status_code == 200, response.text
assert response.json() == {"token": "testtoken"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "security": [{"OAuth2AuthorizationCodeBearer": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "OAuth2AuthorizationCodeBearer": {
+ "type": "oauth2",
+ "flows": {
+ "authorizationCode": {
+ "authorizationUrl": "authorize",
+ "tokenUrl": "token",
+ "scopes": {},
+ }
+ },
+ "description": "OAuth2 Code Bearer",
+ }
+ }
+ },
+ }
diff --git a/tests/test_security_oauth2_optional.py b/tests/test_security_oauth2_optional.py
index a5fd49b8c..3ef9f4a8d 100644
--- a/tests/test_security_oauth2_optional.py
+++ b/tests/test_security_oauth2_optional.py
@@ -44,124 +44,6 @@ def read_users_me(current_user: Optional[User] = Depends(get_current_user)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/login": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Login",
- "operationId": "login_login_post",
- "requestBody": {
- "content": {
- "application/x-www-form-urlencoded": {
- "schema": {
- "$ref": "#/components/schemas/Body_login_login_post"
- }
- }
- },
- "required": True,
- },
- }
- },
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Users Me",
- "operationId": "read_users_me_users_me_get",
- "security": [{"OAuth2": []}],
- }
- },
- },
- "components": {
- "schemas": {
- "Body_login_login_post": {
- "title": "Body_login_login_post",
- "required": ["grant_type", "username", "password"],
- "type": "object",
- "properties": {
- "grant_type": {
- "title": "Grant Type",
- "pattern": "password",
- "type": "string",
- },
- "username": {"title": "Username", "type": "string"},
- "password": {"title": "Password", "type": "string"},
- "scope": {"title": "Scope", "type": "string", "default": ""},
- "client_id": {"title": "Client Id", "type": "string"},
- "client_secret": {"title": "Client Secret", "type": "string"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- },
- "securitySchemes": {
- "OAuth2": {
- "type": "oauth2",
- "flows": {
- "password": {
- "scopes": {
- "read:users": "Read the users",
- "write:users": "Create users",
- },
- "tokenUrl": "token",
- }
- },
- }
- },
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_oauth2():
response = client.get("/users/me", headers={"Authorization": "Bearer footokenbar"})
@@ -251,3 +133,121 @@ def test_strict_login(data, expected_status, expected_response):
response = client.post("/login", data=data)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/login": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Login",
+ "operationId": "login_login_post",
+ "requestBody": {
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_login_login_post"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ },
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Users Me",
+ "operationId": "read_users_me_users_me_get",
+ "security": [{"OAuth2": []}],
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_login_login_post": {
+ "title": "Body_login_login_post",
+ "required": ["grant_type", "username", "password"],
+ "type": "object",
+ "properties": {
+ "grant_type": {
+ "title": "Grant Type",
+ "pattern": "password",
+ "type": "string",
+ },
+ "username": {"title": "Username", "type": "string"},
+ "password": {"title": "Password", "type": "string"},
+ "scope": {"title": "Scope", "type": "string", "default": ""},
+ "client_id": {"title": "Client Id", "type": "string"},
+ "client_secret": {"title": "Client Secret", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ },
+ "securitySchemes": {
+ "OAuth2": {
+ "type": "oauth2",
+ "flows": {
+ "password": {
+ "scopes": {
+ "read:users": "Read the users",
+ "write:users": "Create users",
+ },
+ "tokenUrl": "token",
+ }
+ },
+ }
+ },
+ },
+ }
diff --git a/tests/test_security_oauth2_optional_description.py b/tests/test_security_oauth2_optional_description.py
index 171f96b76..b6425fde4 100644
--- a/tests/test_security_oauth2_optional_description.py
+++ b/tests/test_security_oauth2_optional_description.py
@@ -45,125 +45,6 @@ def read_users_me(current_user: Optional[User] = Depends(get_current_user)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/login": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Login",
- "operationId": "login_login_post",
- "requestBody": {
- "content": {
- "application/x-www-form-urlencoded": {
- "schema": {
- "$ref": "#/components/schemas/Body_login_login_post"
- }
- }
- },
- "required": True,
- },
- }
- },
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Users Me",
- "operationId": "read_users_me_users_me_get",
- "security": [{"OAuth2": []}],
- }
- },
- },
- "components": {
- "schemas": {
- "Body_login_login_post": {
- "title": "Body_login_login_post",
- "required": ["grant_type", "username", "password"],
- "type": "object",
- "properties": {
- "grant_type": {
- "title": "Grant Type",
- "pattern": "password",
- "type": "string",
- },
- "username": {"title": "Username", "type": "string"},
- "password": {"title": "Password", "type": "string"},
- "scope": {"title": "Scope", "type": "string", "default": ""},
- "client_id": {"title": "Client Id", "type": "string"},
- "client_secret": {"title": "Client Secret", "type": "string"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- },
- "securitySchemes": {
- "OAuth2": {
- "type": "oauth2",
- "flows": {
- "password": {
- "scopes": {
- "read:users": "Read the users",
- "write:users": "Create users",
- },
- "tokenUrl": "token",
- }
- },
- "description": "OAuth2 security scheme",
- }
- },
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_oauth2():
response = client.get("/users/me", headers={"Authorization": "Bearer footokenbar"})
@@ -253,3 +134,122 @@ def test_strict_login(data, expected_status, expected_response):
response = client.post("/login", data=data)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/login": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Login",
+ "operationId": "login_login_post",
+ "requestBody": {
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_login_login_post"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ },
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Users Me",
+ "operationId": "read_users_me_users_me_get",
+ "security": [{"OAuth2": []}],
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_login_login_post": {
+ "title": "Body_login_login_post",
+ "required": ["grant_type", "username", "password"],
+ "type": "object",
+ "properties": {
+ "grant_type": {
+ "title": "Grant Type",
+ "pattern": "password",
+ "type": "string",
+ },
+ "username": {"title": "Username", "type": "string"},
+ "password": {"title": "Password", "type": "string"},
+ "scope": {"title": "Scope", "type": "string", "default": ""},
+ "client_id": {"title": "Client Id", "type": "string"},
+ "client_secret": {"title": "Client Secret", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ },
+ "securitySchemes": {
+ "OAuth2": {
+ "type": "oauth2",
+ "flows": {
+ "password": {
+ "scopes": {
+ "read:users": "Read the users",
+ "write:users": "Create users",
+ },
+ "tokenUrl": "token",
+ }
+ },
+ "description": "OAuth2 security scheme",
+ }
+ },
+ },
+ }
diff --git a/tests/test_security_oauth2_password_bearer_optional.py b/tests/test_security_oauth2_password_bearer_optional.py
index 3d6637d4a..e5dcbb553 100644
--- a/tests/test_security_oauth2_password_bearer_optional.py
+++ b/tests/test_security_oauth2_password_bearer_optional.py
@@ -18,40 +18,6 @@ async def read_items(token: Optional[str] = Security(oauth2_scheme)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "security": [{"OAuth2PasswordBearer": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "OAuth2PasswordBearer": {
- "type": "oauth2",
- "flows": {"password": {"scopes": {}, "tokenUrl": "/token"}},
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_no_token():
response = client.get("/items")
@@ -69,3 +35,35 @@ def test_incorrect_token():
response = client.get("/items", headers={"Authorization": "Notexistent testtoken"})
assert response.status_code == 200, response.text
assert response.json() == {"msg": "Create an account first"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "security": [{"OAuth2PasswordBearer": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "OAuth2PasswordBearer": {
+ "type": "oauth2",
+ "flows": {"password": {"scopes": {}, "tokenUrl": "/token"}},
+ }
+ }
+ },
+ }
diff --git a/tests/test_security_oauth2_password_bearer_optional_description.py b/tests/test_security_oauth2_password_bearer_optional_description.py
index 9d6a862e3..9ff48e715 100644
--- a/tests/test_security_oauth2_password_bearer_optional_description.py
+++ b/tests/test_security_oauth2_password_bearer_optional_description.py
@@ -22,41 +22,6 @@ async def read_items(token: Optional[str] = Security(oauth2_scheme)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "security": [{"OAuth2PasswordBearer": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "OAuth2PasswordBearer": {
- "type": "oauth2",
- "flows": {"password": {"scopes": {}, "tokenUrl": "/token"}},
- "description": "OAuth2PasswordBearer security scheme",
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_no_token():
response = client.get("/items")
@@ -74,3 +39,36 @@ def test_incorrect_token():
response = client.get("/items", headers={"Authorization": "Notexistent testtoken"})
assert response.status_code == 200, response.text
assert response.json() == {"msg": "Create an account first"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "security": [{"OAuth2PasswordBearer": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "OAuth2PasswordBearer": {
+ "type": "oauth2",
+ "flows": {"password": {"scopes": {}, "tokenUrl": "/token"}},
+ "description": "OAuth2PasswordBearer security scheme",
+ }
+ }
+ },
+ }
diff --git a/tests/test_security_openid_connect.py b/tests/test_security_openid_connect.py
index 8203961be..206de6574 100644
--- a/tests/test_security_openid_connect.py
+++ b/tests/test_security_openid_connect.py
@@ -24,37 +24,6 @@ def read_current_user(current_user: User = Depends(get_current_user)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"OpenIdConnect": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "OpenIdConnect": {"type": "openIdConnect", "openIdConnectUrl": "/openid"}
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_oauth2():
response = client.get("/users/me", headers={"Authorization": "Bearer footokenbar"})
@@ -72,3 +41,35 @@ def test_security_oauth2_password_bearer_no_header():
response = client.get("/users/me")
assert response.status_code == 403, response.text
assert response.json() == {"detail": "Not authenticated"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"OpenIdConnect": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "OpenIdConnect": {
+ "type": "openIdConnect",
+ "openIdConnectUrl": "/openid",
+ }
+ }
+ },
+ }
diff --git a/tests/test_security_openid_connect_description.py b/tests/test_security_openid_connect_description.py
index 218cbfc8f..5884de793 100644
--- a/tests/test_security_openid_connect_description.py
+++ b/tests/test_security_openid_connect_description.py
@@ -26,41 +26,6 @@ def read_current_user(current_user: User = Depends(get_current_user)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"OpenIdConnect": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "OpenIdConnect": {
- "type": "openIdConnect",
- "openIdConnectUrl": "/openid",
- "description": "OpenIdConnect security scheme",
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_oauth2():
response = client.get("/users/me", headers={"Authorization": "Bearer footokenbar"})
@@ -78,3 +43,36 @@ def test_security_oauth2_password_bearer_no_header():
response = client.get("/users/me")
assert response.status_code == 403, response.text
assert response.json() == {"detail": "Not authenticated"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"OpenIdConnect": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "OpenIdConnect": {
+ "type": "openIdConnect",
+ "openIdConnectUrl": "/openid",
+ "description": "OpenIdConnect security scheme",
+ }
+ }
+ },
+ }
diff --git a/tests/test_security_openid_connect_optional.py b/tests/test_security_openid_connect_optional.py
index 4577dfebb..8ac719118 100644
--- a/tests/test_security_openid_connect_optional.py
+++ b/tests/test_security_openid_connect_optional.py
@@ -30,37 +30,6 @@ def read_current_user(current_user: Optional[User] = Depends(get_current_user)):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/me": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Current User",
- "operationId": "read_current_user_users_me_get",
- "security": [{"OpenIdConnect": []}],
- }
- }
- },
- "components": {
- "securitySchemes": {
- "OpenIdConnect": {"type": "openIdConnect", "openIdConnectUrl": "/openid"}
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_security_oauth2():
response = client.get("/users/me", headers={"Authorization": "Bearer footokenbar"})
@@ -78,3 +47,35 @@ def test_security_oauth2_password_bearer_no_header():
response = client.get("/users/me")
assert response.status_code == 200, response.text
assert response.json() == {"msg": "Create an account first"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/me": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Current User",
+ "operationId": "read_current_user_users_me_get",
+ "security": [{"OpenIdConnect": []}],
+ }
+ }
+ },
+ "components": {
+ "securitySchemes": {
+ "OpenIdConnect": {
+ "type": "openIdConnect",
+ "openIdConnectUrl": "/openid",
+ }
+ }
+ },
+ }
diff --git a/tests/test_starlette_exception.py b/tests/test_starlette_exception.py
index 418ddff7d..96f835b93 100644
--- a/tests/test_starlette_exception.py
+++ b/tests/test_starlette_exception.py
@@ -37,132 +37,6 @@ async def read_starlette_item(item_id: str):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/http-no-body-statuscode-exception": {
- "get": {
- "operationId": "no_body_status_code_exception_http_no_body_statuscode_exception_get",
- "responses": {
- "200": {
- "content": {"application/json": {"schema": {}}},
- "description": "Successful Response",
- }
- },
- "summary": "No Body Status Code Exception",
- }
- },
- "/http-no-body-statuscode-with-detail-exception": {
- "get": {
- "operationId": "no_body_status_code_with_detail_exception_http_no_body_statuscode_with_detail_exception_get",
- "responses": {
- "200": {
- "content": {"application/json": {"schema": {}}},
- "description": "Successful Response",
- }
- },
- "summary": "No Body Status Code With Detail Exception",
- }
- },
- "/items/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Item",
- "operationId": "read_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- "/starlette-items/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Starlette Item",
- "operationId": "read_starlette_item_starlette_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- },
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get_item():
response = client.get("/items/foo")
@@ -200,3 +74,129 @@ def test_no_body_status_code_with_detail_exception_handlers():
response = client.get("/http-no-body-statuscode-with-detail-exception")
assert response.status_code == 204
assert not response.content
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/http-no-body-statuscode-exception": {
+ "get": {
+ "operationId": "no_body_status_code_exception_http_no_body_statuscode_exception_get",
+ "responses": {
+ "200": {
+ "content": {"application/json": {"schema": {}}},
+ "description": "Successful Response",
+ }
+ },
+ "summary": "No Body Status Code Exception",
+ }
+ },
+ "/http-no-body-statuscode-with-detail-exception": {
+ "get": {
+ "operationId": "no_body_status_code_with_detail_exception_http_no_body_statuscode_with_detail_exception_get",
+ "responses": {
+ "200": {
+ "content": {"application/json": {"schema": {}}},
+ "description": "Successful Response",
+ }
+ },
+ "summary": "No Body Status Code With Detail Exception",
+ }
+ },
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ "/starlette-items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Starlette Item",
+ "operationId": "read_starlette_item_starlette_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_sub_callbacks.py b/tests/test_sub_callbacks.py
index 7574d6fbc..c5a0237e8 100644
--- a/tests/test_sub_callbacks.py
+++ b/tests/test_sub_callbacks.py
@@ -74,209 +74,212 @@ app.include_router(subrouter, callbacks=events_callback_router.routes)
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/invoices/": {
- "post": {
- "summary": "Create Invoice",
- "description": 'Create an invoice.\n\nThis will (let\'s imagine) let the API user (some external developer) create an\ninvoice.\n\nAnd this path operation will:\n\n* Send the invoice to the client.\n* Collect the money from the client.\n* Send a notification back to the API user (the external developer), as a callback.\n * At this point is that the API will somehow send a POST request to the\n external API with the notification of the invoice event\n (e.g. "payment successful").',
- "operationId": "create_invoice_invoices__post",
- "parameters": [
- {
- "required": False,
- "schema": {
- "title": "Callback Url",
- "maxLength": 2083,
- "minLength": 1,
- "type": "string",
- "format": "uri",
- },
- "name": "callback_url",
- "in": "query",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Invoice"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
+
+def test_get():
+ response = client.post(
+ "/invoices/", json={"id": "fooinvoice", "customer": "John", "total": 5.3}
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == {"msg": "Invoice received"}
+
+
+def test_openapi_schema():
+ with client:
+ response = client.get("/openapi.json")
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/invoices/": {
+ "post": {
+ "summary": "Create Invoice",
+ "description": 'Create an invoice.\n\nThis will (let\'s imagine) let the API user (some external developer) create an\ninvoice.\n\nAnd this path operation will:\n\n* Send the invoice to the client.\n* Collect the money from the client.\n* Send a notification back to the API user (the external developer), as a callback.\n * At this point is that the API will somehow send a POST request to the\n external API with the notification of the invoice event\n (e.g. "payment successful").',
+ "operationId": "create_invoice_invoices__post",
+ "parameters": [
+ {
+ "required": False,
"schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
+ "title": "Callback Url",
+ "maxLength": 2083,
+ "minLength": 1,
+ "type": "string",
+ "format": "uri",
+ },
+ "name": "callback_url",
+ "in": "query",
}
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Invoice"}
+ }
+ },
+ "required": True,
},
- },
- },
- "callbacks": {
- "event_callback": {
- "{$callback_url}/events/{$request.body.title}": {
- "get": {
- "summary": "Event Callback",
- "operationId": "event_callback__callback_url__events___request_body_title__get",
- "requestBody": {
- "required": True,
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Event"
- }
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
}
- },
+ }
},
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ },
+ },
+ "callbacks": {
+ "event_callback": {
+ "{$callback_url}/events/{$request.body.title}": {
+ "get": {
+ "summary": "Event Callback",
+ "operationId": "event_callback__callback_url__events___request_body_title__get",
+ "requestBody": {
+ "required": True,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Event"
+ }
}
- }
+ },
},
- },
- },
- }
- }
- },
- "invoice_notification": {
- "{$callback_url}/invoices/{$request.body.id}": {
- "post": {
- "summary": "Invoice Notification",
- "operationId": "invoice_notification__callback_url__invoices___request_body_id__post",
- "requestBody": {
- "required": True,
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/InvoiceEvent"
- }
- }
- },
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/InvoiceEventReceived"
- }
- }
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {"schema": {}}
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ "invoice_notification": {
+ "{$callback_url}/invoices/{$request.body.id}": {
+ "post": {
+ "summary": "Invoice Notification",
+ "operationId": "invoice_notification__callback_url__invoices___request_body_id__post",
+ "requestBody": {
+ "required": True,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvoiceEvent"
+ }
}
- }
+ },
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvoiceEventReceived"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
},
- },
+ }
+ }
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Event": {
+ "title": "Event",
+ "required": ["name", "total"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "total": {"title": "Total", "type": "number"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ValidationError"
},
}
- }
+ },
},
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Event": {
- "title": "Event",
- "required": ["name", "total"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "total": {"title": "Total", "type": "number"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "Invoice": {
- "title": "Invoice",
- "required": ["id", "customer", "total"],
- "type": "object",
- "properties": {
- "id": {"title": "Id", "type": "string"},
- "title": {"title": "Title", "type": "string"},
- "customer": {"title": "Customer", "type": "string"},
- "total": {"title": "Total", "type": "number"},
- },
- },
- "InvoiceEvent": {
- "title": "InvoiceEvent",
- "required": ["description", "paid"],
- "type": "object",
- "properties": {
- "description": {"title": "Description", "type": "string"},
- "paid": {"title": "Paid", "type": "boolean"},
- },
- },
- "InvoiceEventReceived": {
- "title": "InvoiceEventReceived",
- "required": ["ok"],
- "type": "object",
- "properties": {"ok": {"title": "Ok", "type": "boolean"}},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ "Invoice": {
+ "title": "Invoice",
+ "required": ["id", "customer", "total"],
+ "type": "object",
+ "properties": {
+ "id": {"title": "Id", "type": "string"},
+ "title": {"title": "Title", "type": "string"},
+ "customer": {"title": "Customer", "type": "string"},
+ "total": {"title": "Total", "type": "number"},
+ },
},
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
+ "InvoiceEvent": {
+ "title": "InvoiceEvent",
+ "required": ["description", "paid"],
+ "type": "object",
+ "properties": {
+ "description": {"title": "Description", "type": "string"},
+ "paid": {"title": "Paid", "type": "boolean"},
+ },
+ },
+ "InvoiceEventReceived": {
+ "title": "InvoiceEventReceived",
+ "required": ["ok"],
+ "type": "object",
+ "properties": {"ok": {"title": "Ok", "type": "boolean"}},
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
},
}
- },
-}
-
-
-def test_openapi():
- with client:
- response = client.get("/openapi.json")
-
- assert response.json() == openapi_schema
-
-
-def test_get():
- response = client.post(
- "/invoices/", json={"id": "fooinvoice", "customer": "John", "total": 5.3}
- )
- assert response.status_code == 200, response.text
- assert response.json() == {"msg": "Invoice received"}
diff --git a/tests/test_tuples.py b/tests/test_tuples.py
index 6e2cc0db6..4fa1f7a13 100644
--- a/tests/test_tuples.py
+++ b/tests/test_tuples.py
@@ -33,189 +33,6 @@ def hello(values: Tuple[int, int] = Form()):
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/model-with-tuple/": {
- "post": {
- "summary": "Post Model With Tuple",
- "operationId": "post_model_with_tuple_model_with_tuple__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/ItemGroup"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- "/tuple-of-models/": {
- "post": {
- "summary": "Post Tuple Of Models",
- "operationId": "post_tuple_of_models_tuple_of_models__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "title": "Square",
- "maxItems": 2,
- "minItems": 2,
- "type": "array",
- "items": [
- {"$ref": "#/components/schemas/Coordinate"},
- {"$ref": "#/components/schemas/Coordinate"},
- ],
- }
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- "/tuple-form/": {
- "post": {
- "summary": "Hello",
- "operationId": "hello_tuple_form__post",
- "requestBody": {
- "content": {
- "application/x-www-form-urlencoded": {
- "schema": {
- "$ref": "#/components/schemas/Body_hello_tuple_form__post"
- }
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- },
- "components": {
- "schemas": {
- "Body_hello_tuple_form__post": {
- "title": "Body_hello_tuple_form__post",
- "required": ["values"],
- "type": "object",
- "properties": {
- "values": {
- "title": "Values",
- "maxItems": 2,
- "minItems": 2,
- "type": "array",
- "items": [{"type": "integer"}, {"type": "integer"}],
- }
- },
- },
- "Coordinate": {
- "title": "Coordinate",
- "required": ["x", "y"],
- "type": "object",
- "properties": {
- "x": {"title": "X", "type": "number"},
- "y": {"title": "Y", "type": "number"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "ItemGroup": {
- "title": "ItemGroup",
- "required": ["items"],
- "type": "object",
- "properties": {
- "items": {
- "title": "Items",
- "type": "array",
- "items": {
- "maxItems": 2,
- "minItems": 2,
- "type": "array",
- "items": [{"type": "string"}, {"type": "string"}],
- },
- }
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_model_with_tuple_valid():
data = {"items": [["foo", "bar"], ["baz", "whatelse"]]}
@@ -263,3 +80,186 @@ def test_tuple_form_invalid():
response = client.post("/tuple-form/", data={"values": ("1")})
assert response.status_code == 422, response.text
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/model-with-tuple/": {
+ "post": {
+ "summary": "Post Model With Tuple",
+ "operationId": "post_model_with_tuple_model_with_tuple__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/ItemGroup"}
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/tuple-of-models/": {
+ "post": {
+ "summary": "Post Tuple Of Models",
+ "operationId": "post_tuple_of_models_tuple_of_models__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Square",
+ "maxItems": 2,
+ "minItems": 2,
+ "type": "array",
+ "items": [
+ {"$ref": "#/components/schemas/Coordinate"},
+ {"$ref": "#/components/schemas/Coordinate"},
+ ],
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/tuple-form/": {
+ "post": {
+ "summary": "Hello",
+ "operationId": "hello_tuple_form__post",
+ "requestBody": {
+ "content": {
+ "application/x-www-form-urlencoded": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_hello_tuple_form__post"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_hello_tuple_form__post": {
+ "title": "Body_hello_tuple_form__post",
+ "required": ["values"],
+ "type": "object",
+ "properties": {
+ "values": {
+ "title": "Values",
+ "maxItems": 2,
+ "minItems": 2,
+ "type": "array",
+ "items": [{"type": "integer"}, {"type": "integer"}],
+ }
+ },
+ },
+ "Coordinate": {
+ "title": "Coordinate",
+ "required": ["x", "y"],
+ "type": "object",
+ "properties": {
+ "x": {"title": "X", "type": "number"},
+ "y": {"title": "Y", "type": "number"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ItemGroup": {
+ "title": "ItemGroup",
+ "required": ["items"],
+ "type": "object",
+ "properties": {
+ "items": {
+ "title": "Items",
+ "type": "array",
+ "items": {
+ "maxItems": 2,
+ "minItems": 2,
+ "type": "array",
+ "items": [{"type": "string"}, {"type": "string"}],
+ },
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial001.py b/tests/test_tutorial/test_additional_responses/test_tutorial001.py
index 1a8acb523..3d6267023 100644
--- a/tests/test_tutorial/test_additional_responses/test_tutorial001.py
+++ b/tests/test_tutorial/test_additional_responses/test_tutorial001.py
@@ -4,105 +4,6 @@ from docs_src.additional_responses.tutorial001 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "404": {
- "description": "Not Found",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Message"}
- }
- },
- },
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Item",
- "operationId": "read_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["id", "value"],
- "type": "object",
- "properties": {
- "id": {"title": "Id", "type": "string"},
- "value": {"title": "Value", "type": "string"},
- },
- },
- "Message": {
- "title": "Message",
- "required": ["message"],
- "type": "object",
- "properties": {"message": {"title": "Message", "type": "string"}},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_path_operation():
response = client.get("/items/foo")
@@ -114,3 +15,102 @@ def test_path_operation_not_found():
response = client.get("/items/bar")
assert response.status_code == 404, response.text
assert response.json() == {"message": "Item not found"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "404": {
+ "description": "Not Found",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Message"}
+ }
+ },
+ },
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["id", "value"],
+ "type": "object",
+ "properties": {
+ "id": {"title": "Id", "type": "string"},
+ "value": {"title": "Value", "type": "string"},
+ },
+ },
+ "Message": {
+ "title": "Message",
+ "required": ["message"],
+ "type": "object",
+ "properties": {"message": {"title": "Message", "type": "string"}},
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial002.py b/tests/test_tutorial/test_additional_responses/test_tutorial002.py
index 2adcf15d0..6182ed507 100644
--- a/tests/test_tutorial/test_additional_responses/test_tutorial002.py
+++ b/tests/test_tutorial/test_additional_responses/test_tutorial002.py
@@ -7,98 +7,6 @@ from docs_src.additional_responses.tutorial002 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Return the JSON item or an image.",
- "content": {
- "image/png": {},
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- },
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Item",
- "operationId": "read_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- },
- {
- "required": False,
- "schema": {"title": "Img", "type": "boolean"},
- "name": "img",
- "in": "query",
- },
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["id", "value"],
- "type": "object",
- "properties": {
- "id": {"title": "Id", "type": "string"},
- "value": {"title": "Value", "type": "string"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_path_operation():
response = client.get("/items/foo")
@@ -113,3 +21,95 @@ def test_path_operation_img():
assert response.headers["Content-Type"] == "image/png"
assert len(response.content)
os.remove("./image.png")
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Return the JSON item or an image.",
+ "content": {
+ "image/png": {},
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ },
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ },
+ {
+ "required": False,
+ "schema": {"title": "Img", "type": "boolean"},
+ "name": "img",
+ "in": "query",
+ },
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["id", "value"],
+ "type": "object",
+ "properties": {
+ "id": {"title": "Id", "type": "string"},
+ "value": {"title": "Value", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial003.py b/tests/test_tutorial/test_additional_responses/test_tutorial003.py
index 8b2167de0..77568d9d4 100644
--- a/tests/test_tutorial/test_additional_responses/test_tutorial003.py
+++ b/tests/test_tutorial/test_additional_responses/test_tutorial003.py
@@ -4,106 +4,6 @@ from docs_src.additional_responses.tutorial003 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "404": {
- "description": "The item was not found",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Message"}
- }
- },
- },
- "200": {
- "description": "Item requested by ID",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"},
- "example": {"id": "bar", "value": "The bar tenders"},
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Item",
- "operationId": "read_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["id", "value"],
- "type": "object",
- "properties": {
- "id": {"title": "Id", "type": "string"},
- "value": {"title": "Value", "type": "string"},
- },
- },
- "Message": {
- "title": "Message",
- "required": ["message"],
- "type": "object",
- "properties": {"message": {"title": "Message", "type": "string"}},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_path_operation():
response = client.get("/items/foo")
@@ -115,3 +15,106 @@ def test_path_operation_not_found():
response = client.get("/items/bar")
assert response.status_code == 404, response.text
assert response.json() == {"message": "Item not found"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "404": {
+ "description": "The item was not found",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Message"}
+ }
+ },
+ },
+ "200": {
+ "description": "Item requested by ID",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"},
+ "example": {
+ "id": "bar",
+ "value": "The bar tenders",
+ },
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["id", "value"],
+ "type": "object",
+ "properties": {
+ "id": {"title": "Id", "type": "string"},
+ "value": {"title": "Value", "type": "string"},
+ },
+ },
+ "Message": {
+ "title": "Message",
+ "required": ["message"],
+ "type": "object",
+ "properties": {"message": {"title": "Message", "type": "string"}},
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial004.py b/tests/test_tutorial/test_additional_responses/test_tutorial004.py
index 990d5235a..3fbd91e5c 100644
--- a/tests/test_tutorial/test_additional_responses/test_tutorial004.py
+++ b/tests/test_tutorial/test_additional_responses/test_tutorial004.py
@@ -7,101 +7,6 @@ from docs_src.additional_responses.tutorial004 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "404": {"description": "Item not found"},
- "302": {"description": "The item was moved"},
- "403": {"description": "Not enough privileges"},
- "200": {
- "description": "Successful Response",
- "content": {
- "image/png": {},
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- },
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Item",
- "operationId": "read_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- },
- {
- "required": False,
- "schema": {"title": "Img", "type": "boolean"},
- "name": "img",
- "in": "query",
- },
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["id", "value"],
- "type": "object",
- "properties": {
- "id": {"title": "Id", "type": "string"},
- "value": {"title": "Value", "type": "string"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_path_operation():
response = client.get("/items/foo")
@@ -116,3 +21,98 @@ def test_path_operation_img():
assert response.headers["Content-Type"] == "image/png"
assert len(response.content)
os.remove("./image.png")
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "404": {"description": "Item not found"},
+ "302": {"description": "The item was moved"},
+ "403": {"description": "Not enough privileges"},
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "image/png": {},
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ },
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ },
+ {
+ "required": False,
+ "schema": {"title": "Img", "type": "boolean"},
+ "name": "img",
+ "in": "query",
+ },
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["id", "value"],
+ "type": "object",
+ "properties": {
+ "id": {"title": "Id", "type": "string"},
+ "value": {"title": "Value", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_additional_status_codes/test_tutorial001_an.py b/tests/test_tutorial/test_additional_status_codes/test_tutorial001_an.py
new file mode 100644
index 000000000..2cb2bb993
--- /dev/null
+++ b/tests/test_tutorial/test_additional_status_codes/test_tutorial001_an.py
@@ -0,0 +1,17 @@
+from fastapi.testclient import TestClient
+
+from docs_src.additional_status_codes.tutorial001_an import app
+
+client = TestClient(app)
+
+
+def test_update():
+ response = client.put("/items/foo", json={"name": "Wrestlers"})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "Wrestlers", "size": None}
+
+
+def test_create():
+ response = client.put("/items/red", json={"name": "Chillies"})
+ assert response.status_code == 201, response.text
+ assert response.json() == {"name": "Chillies", "size": None}
diff --git a/tests/test_tutorial/test_additional_status_codes/test_tutorial001_an_py310.py b/tests/test_tutorial/test_additional_status_codes/test_tutorial001_an_py310.py
new file mode 100644
index 000000000..c7660a392
--- /dev/null
+++ b/tests/test_tutorial/test_additional_status_codes/test_tutorial001_an_py310.py
@@ -0,0 +1,26 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.additional_status_codes.tutorial001_an_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py310
+def test_update(client: TestClient):
+ response = client.put("/items/foo", json={"name": "Wrestlers"})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "Wrestlers", "size": None}
+
+
+@needs_py310
+def test_create(client: TestClient):
+ response = client.put("/items/red", json={"name": "Chillies"})
+ assert response.status_code == 201, response.text
+ assert response.json() == {"name": "Chillies", "size": None}
diff --git a/tests/test_tutorial/test_additional_status_codes/test_tutorial001_an_py39.py b/tests/test_tutorial/test_additional_status_codes/test_tutorial001_an_py39.py
new file mode 100644
index 000000000..303c5dbae
--- /dev/null
+++ b/tests/test_tutorial/test_additional_status_codes/test_tutorial001_an_py39.py
@@ -0,0 +1,26 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.additional_status_codes.tutorial001_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py39
+def test_update(client: TestClient):
+ response = client.put("/items/foo", json={"name": "Wrestlers"})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "Wrestlers", "size": None}
+
+
+@needs_py39
+def test_create(client: TestClient):
+ response = client.put("/items/red", json={"name": "Chillies"})
+ assert response.status_code == 201, response.text
+ assert response.json() == {"name": "Chillies", "size": None}
diff --git a/tests/test_tutorial/test_additional_status_codes/test_tutorial001_py310.py b/tests/test_tutorial/test_additional_status_codes/test_tutorial001_py310.py
new file mode 100644
index 000000000..02f2e188c
--- /dev/null
+++ b/tests/test_tutorial/test_additional_status_codes/test_tutorial001_py310.py
@@ -0,0 +1,26 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.additional_status_codes.tutorial001_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py310
+def test_update(client: TestClient):
+ response = client.put("/items/foo", json={"name": "Wrestlers"})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"name": "Wrestlers", "size": None}
+
+
+@needs_py310
+def test_create(client: TestClient):
+ response = client.put("/items/red", json={"name": "Chillies"})
+ assert response.status_code == 201, response.text
+ assert response.json() == {"name": "Chillies", "size": None}
diff --git a/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py b/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py
index 1ad625db6..3da362a50 100644
--- a/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py
+++ b/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py
@@ -2,120 +2,6 @@ from fastapi.testclient import TestClient
from docs_src.async_sql_databases.tutorial001 import app
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/notes/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Read Notes Notes Get",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Note"},
- }
- }
- },
- }
- },
- "summary": "Read Notes",
- "operationId": "read_notes_notes__get",
- },
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Note"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Create Note",
- "operationId": "create_note_notes__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/NoteIn"}
- }
- },
- "required": True,
- },
- },
- }
- },
- "components": {
- "schemas": {
- "NoteIn": {
- "title": "NoteIn",
- "required": ["text", "completed"],
- "type": "object",
- "properties": {
- "text": {"title": "Text", "type": "string"},
- "completed": {"title": "Completed", "type": "boolean"},
- },
- },
- "Note": {
- "title": "Note",
- "required": ["id", "text", "completed"],
- "type": "object",
- "properties": {
- "id": {"title": "Id", "type": "integer"},
- "text": {"title": "Text", "type": "string"},
- "completed": {"title": "Completed", "type": "boolean"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- with TestClient(app) as client:
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_create_read():
with TestClient(app) as client:
@@ -129,3 +15,121 @@ def test_create_read():
response = client.get("/notes/")
assert response.status_code == 200, response.text
assert data in response.json()
+
+
+def test_openapi_schema():
+ with TestClient(app) as client:
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/notes/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Read Notes Notes Get",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Note"
+ },
+ }
+ }
+ },
+ }
+ },
+ "summary": "Read Notes",
+ "operationId": "read_notes_notes__get",
+ },
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Note"}
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create Note",
+ "operationId": "create_note_notes__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/NoteIn"}
+ }
+ },
+ "required": True,
+ },
+ },
+ }
+ },
+ "components": {
+ "schemas": {
+ "NoteIn": {
+ "title": "NoteIn",
+ "required": ["text", "completed"],
+ "type": "object",
+ "properties": {
+ "text": {"title": "Text", "type": "string"},
+ "completed": {"title": "Completed", "type": "boolean"},
+ },
+ },
+ "Note": {
+ "title": "Note",
+ "required": ["id", "text", "completed"],
+ "type": "object",
+ "properties": {
+ "id": {"title": "Id", "type": "integer"},
+ "text": {"title": "Text", "type": "string"},
+ "completed": {"title": "Completed", "type": "boolean"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ValidationError"
+ },
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_background_tasks/test_tutorial002_an.py b/tests/test_tutorial/test_background_tasks/test_tutorial002_an.py
new file mode 100644
index 000000000..af682ecff
--- /dev/null
+++ b/tests/test_tutorial/test_background_tasks/test_tutorial002_an.py
@@ -0,0 +1,19 @@
+import os
+from pathlib import Path
+
+from fastapi.testclient import TestClient
+
+from docs_src.background_tasks.tutorial002_an import app
+
+client = TestClient(app)
+
+
+def test():
+ log = Path("log.txt")
+ if log.is_file():
+ os.remove(log) # pragma: no cover
+ response = client.post("/send-notification/foo@example.com?q=some-query")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"message": "Message sent"}
+ with open("./log.txt") as f:
+ assert "found query: some-query\nmessage to foo@example.com" in f.read()
diff --git a/tests/test_tutorial/test_background_tasks/test_tutorial002_an_py310.py b/tests/test_tutorial/test_background_tasks/test_tutorial002_an_py310.py
new file mode 100644
index 000000000..067b2787e
--- /dev/null
+++ b/tests/test_tutorial/test_background_tasks/test_tutorial002_an_py310.py
@@ -0,0 +1,21 @@
+import os
+from pathlib import Path
+
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@needs_py310
+def test():
+ from docs_src.background_tasks.tutorial002_an_py310 import app
+
+ client = TestClient(app)
+ log = Path("log.txt")
+ if log.is_file():
+ os.remove(log) # pragma: no cover
+ response = client.post("/send-notification/foo@example.com?q=some-query")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"message": "Message sent"}
+ with open("./log.txt") as f:
+ assert "found query: some-query\nmessage to foo@example.com" in f.read()
diff --git a/tests/test_tutorial/test_background_tasks/test_tutorial002_an_py39.py b/tests/test_tutorial/test_background_tasks/test_tutorial002_an_py39.py
new file mode 100644
index 000000000..06b5a2f57
--- /dev/null
+++ b/tests/test_tutorial/test_background_tasks/test_tutorial002_an_py39.py
@@ -0,0 +1,21 @@
+import os
+from pathlib import Path
+
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@needs_py39
+def test():
+ from docs_src.background_tasks.tutorial002_an_py39 import app
+
+ client = TestClient(app)
+ log = Path("log.txt")
+ if log.is_file():
+ os.remove(log) # pragma: no cover
+ response = client.post("/send-notification/foo@example.com?q=some-query")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"message": "Message sent"}
+ with open("./log.txt") as f:
+ assert "found query: some-query\nmessage to foo@example.com" in f.read()
diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py
index be9e499bf..7533a1b68 100644
--- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py
+++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py
@@ -4,34 +4,32 @@ from docs_src.behind_a_proxy.tutorial001 import app
client = TestClient(app, root_path="/api/v1")
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/app": {
- "get": {
- "summary": "Read Main",
- "operationId": "read_main_app_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- }
- }
- },
- "servers": [{"url": "/api/v1"}],
-}
-
-
-def test_openapi():
- response = client.get("/openapi.json")
- assert response.status_code == 200
- assert response.json() == openapi_schema
-
def test_main():
response = client.get("/app")
assert response.status_code == 200
assert response.json() == {"message": "Hello World", "root_path": "/api/v1"}
+
+
+def test_openapi():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/app": {
+ "get": {
+ "summary": "Read Main",
+ "operationId": "read_main_app_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ }
+ },
+ "servers": [{"url": "/api/v1"}],
+ }
diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py
index ac192e3db..930ab3bf5 100644
--- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py
+++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py
@@ -4,34 +4,32 @@ from docs_src.behind_a_proxy.tutorial002 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/app": {
- "get": {
- "summary": "Read Main",
- "operationId": "read_main_app_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- }
- }
- },
- "servers": [{"url": "/api/v1"}],
-}
-
-
-def test_openapi():
- response = client.get("/openapi.json")
- assert response.status_code == 200
- assert response.json() == openapi_schema
-
def test_main():
response = client.get("/app")
assert response.status_code == 200
assert response.json() == {"message": "Hello World", "root_path": "/api/v1"}
+
+
+def test_openapi():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/app": {
+ "get": {
+ "summary": "Read Main",
+ "operationId": "read_main_app_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ }
+ },
+ "servers": [{"url": "/api/v1"}],
+ }
diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py
index 2727525ca..ae8f1a495 100644
--- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py
+++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py
@@ -4,38 +4,39 @@ from docs_src.behind_a_proxy.tutorial003 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "servers": [
- {"url": "/api/v1"},
- {"url": "https://stag.example.com", "description": "Staging environment"},
- {"url": "https://prod.example.com", "description": "Production environment"},
- ],
- "paths": {
- "/app": {
- "get": {
- "summary": "Read Main",
- "operationId": "read_main_app_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- }
- }
- },
-}
-
-
-def test_openapi():
- response = client.get("/openapi.json")
- assert response.status_code == 200
- assert response.json() == openapi_schema
-
def test_main():
response = client.get("/app")
assert response.status_code == 200
assert response.json() == {"message": "Hello World", "root_path": "/api/v1"}
+
+
+def test_openapi():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "servers": [
+ {"url": "/api/v1"},
+ {"url": "https://stag.example.com", "description": "Staging environment"},
+ {
+ "url": "https://prod.example.com",
+ "description": "Production environment",
+ },
+ ],
+ "paths": {
+ "/app": {
+ "get": {
+ "summary": "Read Main",
+ "operationId": "read_main_app_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py
index 4c4e4b75c..e67ad1cb1 100644
--- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py
+++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py
@@ -4,37 +4,38 @@ from docs_src.behind_a_proxy.tutorial004 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "servers": [
- {"url": "https://stag.example.com", "description": "Staging environment"},
- {"url": "https://prod.example.com", "description": "Production environment"},
- ],
- "paths": {
- "/app": {
- "get": {
- "summary": "Read Main",
- "operationId": "read_main_app_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- }
- }
- },
-}
-
-
-def test_openapi():
- response = client.get("/openapi.json")
- assert response.status_code == 200
- assert response.json() == openapi_schema
-
def test_main():
response = client.get("/app")
assert response.status_code == 200
assert response.json() == {"message": "Hello World", "root_path": "/api/v1"}
+
+
+def test_openapi():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "servers": [
+ {"url": "https://stag.example.com", "description": "Staging environment"},
+ {
+ "url": "https://prod.example.com",
+ "description": "Production environment",
+ },
+ ],
+ "paths": {
+ "/app": {
+ "get": {
+ "summary": "Read Main",
+ "operationId": "read_main_app_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_bigger_applications/test_main.py b/tests/test_tutorial/test_bigger_applications/test_main.py
index cd6d7b5c8..a13decd75 100644
--- a/tests/test_tutorial/test_bigger_applications/test_main.py
+++ b/tests/test_tutorial/test_bigger_applications/test_main.py
@@ -5,334 +5,6 @@ from docs_src.bigger_applications.app.main import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/": {
- "get": {
- "tags": ["users"],
- "summary": "Read Users",
- "operationId": "read_users_users__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Token", "type": "string"},
- "name": "token",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- "/users/me": {
- "get": {
- "tags": ["users"],
- "summary": "Read User Me",
- "operationId": "read_user_me_users_me_get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Token", "type": "string"},
- "name": "token",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- "/users/{username}": {
- "get": {
- "tags": ["users"],
- "summary": "Read User",
- "operationId": "read_user_users__username__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Username", "type": "string"},
- "name": "username",
- "in": "path",
- },
- {
- "required": True,
- "schema": {"title": "Token", "type": "string"},
- "name": "token",
- "in": "query",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- "/items/": {
- "get": {
- "tags": ["items"],
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Token", "type": "string"},
- "name": "token",
- "in": "query",
- },
- {
- "required": True,
- "schema": {"title": "X-Token", "type": "string"},
- "name": "x-token",
- "in": "header",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "404": {"description": "Not found"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- "/items/{item_id}": {
- "get": {
- "tags": ["items"],
- "summary": "Read Item",
- "operationId": "read_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- },
- {
- "required": True,
- "schema": {"title": "Token", "type": "string"},
- "name": "token",
- "in": "query",
- },
- {
- "required": True,
- "schema": {"title": "X-Token", "type": "string"},
- "name": "x-token",
- "in": "header",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "404": {"description": "Not found"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "put": {
- "tags": ["items", "custom"],
- "summary": "Update Item",
- "operationId": "update_item_items__item_id__put",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- },
- {
- "required": True,
- "schema": {"title": "Token", "type": "string"},
- "name": "token",
- "in": "query",
- },
- {
- "required": True,
- "schema": {"title": "X-Token", "type": "string"},
- "name": "x-token",
- "in": "header",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "404": {"description": "Not found"},
- "403": {"description": "Operation forbidden"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- },
- "/admin/": {
- "post": {
- "tags": ["admin"],
- "summary": "Update Admin",
- "operationId": "update_admin_admin__post",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Token", "type": "string"},
- "name": "token",
- "in": "query",
- },
- {
- "required": True,
- "schema": {"title": "X-Token", "type": "string"},
- "name": "x-token",
- "in": "header",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "418": {"description": "I'm a teapot"},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- "/": {
- "get": {
- "summary": "Root",
- "operationId": "root__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Token", "type": "string"},
- "name": "token",
- "in": "query",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
no_jessica = {
"detail": [
@@ -427,7 +99,6 @@ no_jessica = {
),
("/?token=jessica", 200, {"message": "Hello Bigger Applications!"}, {}),
("/", 422, no_jessica, {}),
- ("/openapi.json", 200, openapi_schema, {}),
],
)
def test_get_path(path, expected_status, expected_response, headers):
@@ -489,3 +160,337 @@ def test_admin_invalid_header():
response = client.post("/admin/", headers={"X-Token": "invalid"})
assert response.status_code == 400, response.text
assert response.json() == {"detail": "X-Token header invalid"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/": {
+ "get": {
+ "tags": ["users"],
+ "summary": "Read Users",
+ "operationId": "read_users_users__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/users/me": {
+ "get": {
+ "tags": ["users"],
+ "summary": "Read User Me",
+ "operationId": "read_user_me_users_me_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/users/{username}": {
+ "get": {
+ "tags": ["users"],
+ "summary": "Read User",
+ "operationId": "read_user_users__username__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Username", "type": "string"},
+ "name": "username",
+ "in": "path",
+ },
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/items/": {
+ "get": {
+ "tags": ["items"],
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "404": {"description": "Not found"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/items/{item_id}": {
+ "get": {
+ "tags": ["items"],
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ },
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "404": {"description": "Not found"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "put": {
+ "tags": ["items", "custom"],
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ },
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "404": {"description": "Not found"},
+ "403": {"description": "Operation forbidden"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ "/admin/": {
+ "post": {
+ "tags": ["admin"],
+ "summary": "Update Admin",
+ "operationId": "update_admin_admin__post",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "418": {"description": "I'm a teapot"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/": {
+ "get": {
+ "summary": "Root",
+ "operationId": "root__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_bigger_applications/test_main_an.py b/tests/test_tutorial/test_bigger_applications/test_main_an.py
new file mode 100644
index 000000000..64e19c3f3
--- /dev/null
+++ b/tests/test_tutorial/test_bigger_applications/test_main_an.py
@@ -0,0 +1,496 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from docs_src.bigger_applications.app_an.main import app
+
+client = TestClient(app)
+
+
+no_jessica = {
+ "detail": [
+ {
+ "loc": ["query", "token"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ ]
+}
+
+
+@pytest.mark.parametrize(
+ "path,expected_status,expected_response,headers",
+ [
+ (
+ "/users?token=jessica",
+ 200,
+ [{"username": "Rick"}, {"username": "Morty"}],
+ {},
+ ),
+ ("/users", 422, no_jessica, {}),
+ ("/users/foo?token=jessica", 200, {"username": "foo"}, {}),
+ ("/users/foo", 422, no_jessica, {}),
+ ("/users/me?token=jessica", 200, {"username": "fakecurrentuser"}, {}),
+ ("/users/me", 422, no_jessica, {}),
+ (
+ "/users?token=monica",
+ 400,
+ {"detail": "No Jessica token provided"},
+ {},
+ ),
+ (
+ "/items?token=jessica",
+ 200,
+ {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}},
+ {"X-Token": "fake-super-secret-token"},
+ ),
+ ("/items", 422, no_jessica, {"X-Token": "fake-super-secret-token"}),
+ (
+ "/items/plumbus?token=jessica",
+ 200,
+ {"name": "Plumbus", "item_id": "plumbus"},
+ {"X-Token": "fake-super-secret-token"},
+ ),
+ (
+ "/items/bar?token=jessica",
+ 404,
+ {"detail": "Item not found"},
+ {"X-Token": "fake-super-secret-token"},
+ ),
+ ("/items/plumbus", 422, no_jessica, {"X-Token": "fake-super-secret-token"}),
+ (
+ "/items?token=jessica",
+ 400,
+ {"detail": "X-Token header invalid"},
+ {"X-Token": "invalid"},
+ ),
+ (
+ "/items/bar?token=jessica",
+ 400,
+ {"detail": "X-Token header invalid"},
+ {"X-Token": "invalid"},
+ ),
+ (
+ "/items?token=jessica",
+ 422,
+ {
+ "detail": [
+ {
+ "loc": ["header", "x-token"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ }
+ ]
+ },
+ {},
+ ),
+ (
+ "/items/plumbus?token=jessica",
+ 422,
+ {
+ "detail": [
+ {
+ "loc": ["header", "x-token"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ }
+ ]
+ },
+ {},
+ ),
+ ("/?token=jessica", 200, {"message": "Hello Bigger Applications!"}, {}),
+ ("/", 422, no_jessica, {}),
+ ],
+)
+def test_get_path(path, expected_status, expected_response, headers):
+ response = client.get(path, headers=headers)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+def test_put_no_header():
+ response = client.put("/items/foo")
+ assert response.status_code == 422, response.text
+ assert response.json() == {
+ "detail": [
+ {
+ "loc": ["query", "token"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["header", "x-token"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ ]
+ }
+
+
+def test_put_invalid_header():
+ response = client.put("/items/foo", headers={"X-Token": "invalid"})
+ assert response.status_code == 400, response.text
+ assert response.json() == {"detail": "X-Token header invalid"}
+
+
+def test_put():
+ response = client.put(
+ "/items/plumbus?token=jessica", headers={"X-Token": "fake-super-secret-token"}
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == {"item_id": "plumbus", "name": "The great Plumbus"}
+
+
+def test_put_forbidden():
+ response = client.put(
+ "/items/bar?token=jessica", headers={"X-Token": "fake-super-secret-token"}
+ )
+ assert response.status_code == 403, response.text
+ assert response.json() == {"detail": "You can only update the item: plumbus"}
+
+
+def test_admin():
+ response = client.post(
+ "/admin/?token=jessica", headers={"X-Token": "fake-super-secret-token"}
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == {"message": "Admin getting schwifty"}
+
+
+def test_admin_invalid_header():
+ response = client.post("/admin/", headers={"X-Token": "invalid"})
+ assert response.status_code == 400, response.text
+ assert response.json() == {"detail": "X-Token header invalid"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/": {
+ "get": {
+ "tags": ["users"],
+ "summary": "Read Users",
+ "operationId": "read_users_users__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/users/me": {
+ "get": {
+ "tags": ["users"],
+ "summary": "Read User Me",
+ "operationId": "read_user_me_users_me_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/users/{username}": {
+ "get": {
+ "tags": ["users"],
+ "summary": "Read User",
+ "operationId": "read_user_users__username__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Username", "type": "string"},
+ "name": "username",
+ "in": "path",
+ },
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/items/": {
+ "get": {
+ "tags": ["items"],
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "404": {"description": "Not found"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/items/{item_id}": {
+ "get": {
+ "tags": ["items"],
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ },
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "404": {"description": "Not found"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "put": {
+ "tags": ["items", "custom"],
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ },
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "404": {"description": "Not found"},
+ "403": {"description": "Operation forbidden"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ "/admin/": {
+ "post": {
+ "tags": ["admin"],
+ "summary": "Update Admin",
+ "operationId": "update_admin_admin__post",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "418": {"description": "I'm a teapot"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/": {
+ "get": {
+ "summary": "Root",
+ "operationId": "root__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_bigger_applications/test_main_an_py39.py b/tests/test_tutorial/test_bigger_applications/test_main_an_py39.py
new file mode 100644
index 000000000..70c86b4d7
--- /dev/null
+++ b/tests/test_tutorial/test_bigger_applications/test_main_an_py39.py
@@ -0,0 +1,511 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+no_jessica = {
+ "detail": [
+ {
+ "loc": ["query", "token"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ ]
+}
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.bigger_applications.app_an_py39.main import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py39
+@pytest.mark.parametrize(
+ "path,expected_status,expected_response,headers",
+ [
+ (
+ "/users?token=jessica",
+ 200,
+ [{"username": "Rick"}, {"username": "Morty"}],
+ {},
+ ),
+ ("/users", 422, no_jessica, {}),
+ ("/users/foo?token=jessica", 200, {"username": "foo"}, {}),
+ ("/users/foo", 422, no_jessica, {}),
+ ("/users/me?token=jessica", 200, {"username": "fakecurrentuser"}, {}),
+ ("/users/me", 422, no_jessica, {}),
+ (
+ "/users?token=monica",
+ 400,
+ {"detail": "No Jessica token provided"},
+ {},
+ ),
+ (
+ "/items?token=jessica",
+ 200,
+ {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}},
+ {"X-Token": "fake-super-secret-token"},
+ ),
+ ("/items", 422, no_jessica, {"X-Token": "fake-super-secret-token"}),
+ (
+ "/items/plumbus?token=jessica",
+ 200,
+ {"name": "Plumbus", "item_id": "plumbus"},
+ {"X-Token": "fake-super-secret-token"},
+ ),
+ (
+ "/items/bar?token=jessica",
+ 404,
+ {"detail": "Item not found"},
+ {"X-Token": "fake-super-secret-token"},
+ ),
+ ("/items/plumbus", 422, no_jessica, {"X-Token": "fake-super-secret-token"}),
+ (
+ "/items?token=jessica",
+ 400,
+ {"detail": "X-Token header invalid"},
+ {"X-Token": "invalid"},
+ ),
+ (
+ "/items/bar?token=jessica",
+ 400,
+ {"detail": "X-Token header invalid"},
+ {"X-Token": "invalid"},
+ ),
+ (
+ "/items?token=jessica",
+ 422,
+ {
+ "detail": [
+ {
+ "loc": ["header", "x-token"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ }
+ ]
+ },
+ {},
+ ),
+ (
+ "/items/plumbus?token=jessica",
+ 422,
+ {
+ "detail": [
+ {
+ "loc": ["header", "x-token"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ }
+ ]
+ },
+ {},
+ ),
+ ("/?token=jessica", 200, {"message": "Hello Bigger Applications!"}, {}),
+ ("/", 422, no_jessica, {}),
+ ],
+)
+def test_get_path(
+ path, expected_status, expected_response, headers, client: TestClient
+):
+ response = client.get(path, headers=headers)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py39
+def test_put_no_header(client: TestClient):
+ response = client.put("/items/foo")
+ assert response.status_code == 422, response.text
+ assert response.json() == {
+ "detail": [
+ {
+ "loc": ["query", "token"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["header", "x-token"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ ]
+ }
+
+
+@needs_py39
+def test_put_invalid_header(client: TestClient):
+ response = client.put("/items/foo", headers={"X-Token": "invalid"})
+ assert response.status_code == 400, response.text
+ assert response.json() == {"detail": "X-Token header invalid"}
+
+
+@needs_py39
+def test_put(client: TestClient):
+ response = client.put(
+ "/items/plumbus?token=jessica", headers={"X-Token": "fake-super-secret-token"}
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == {"item_id": "plumbus", "name": "The great Plumbus"}
+
+
+@needs_py39
+def test_put_forbidden(client: TestClient):
+ response = client.put(
+ "/items/bar?token=jessica", headers={"X-Token": "fake-super-secret-token"}
+ )
+ assert response.status_code == 403, response.text
+ assert response.json() == {"detail": "You can only update the item: plumbus"}
+
+
+@needs_py39
+def test_admin(client: TestClient):
+ response = client.post(
+ "/admin/?token=jessica", headers={"X-Token": "fake-super-secret-token"}
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == {"message": "Admin getting schwifty"}
+
+
+@needs_py39
+def test_admin_invalid_header(client: TestClient):
+ response = client.post("/admin/", headers={"X-Token": "invalid"})
+ assert response.status_code == 400, response.text
+ assert response.json() == {"detail": "X-Token header invalid"}
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/": {
+ "get": {
+ "tags": ["users"],
+ "summary": "Read Users",
+ "operationId": "read_users_users__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/users/me": {
+ "get": {
+ "tags": ["users"],
+ "summary": "Read User Me",
+ "operationId": "read_user_me_users_me_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/users/{username}": {
+ "get": {
+ "tags": ["users"],
+ "summary": "Read User",
+ "operationId": "read_user_users__username__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Username", "type": "string"},
+ "name": "username",
+ "in": "path",
+ },
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/items/": {
+ "get": {
+ "tags": ["items"],
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "404": {"description": "Not found"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/items/{item_id}": {
+ "get": {
+ "tags": ["items"],
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ },
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "404": {"description": "Not found"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "put": {
+ "tags": ["items", "custom"],
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ },
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "404": {"description": "Not found"},
+ "403": {"description": "Operation forbidden"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ "/admin/": {
+ "post": {
+ "tags": ["admin"],
+ "summary": "Update Admin",
+ "operationId": "update_admin_admin__post",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "418": {"description": "I'm a teapot"},
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/": {
+ "get": {
+ "summary": "Root",
+ "operationId": "root__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Token", "type": "string"},
+ "name": "token",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body/test_tutorial001.py b/tests/test_tutorial/test_body/test_tutorial001.py
index 65cdc758a..cd1209ade 100644
--- a/tests/test_tutorial/test_body/test_tutorial001.py
+++ b/tests/test_tutorial/test_body/test_tutorial001.py
@@ -7,89 +7,6 @@ from docs_src.body.tutorial001 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Create Item",
- "operationId": "create_item_items__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- "description": {"title": "Description", "type": "string"},
- "tax": {"title": "Tax", "type": "number"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
price_missing = {
"detail": [
@@ -277,3 +194,86 @@ def test_other_exceptions():
with patch("json.loads", side_effect=Exception):
response = client.post("/items/", json={"test": "test2"})
assert response.status_code == 400, response.text
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create Item",
+ "operationId": "create_item_items__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body/test_tutorial001_py310.py b/tests/test_tutorial/test_body/test_tutorial001_py310.py
index 83bcb68f3..5ebcbbf57 100644
--- a/tests/test_tutorial/test_body/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_body/test_tutorial001_py310.py
@@ -5,83 +5,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py310
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Create Item",
- "operationId": "create_item_items__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- "description": {"title": "Description", "type": "string"},
- "tax": {"title": "Tax", "type": "number"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture
def client():
@@ -91,13 +14,6 @@ def client():
return client
-@needs_py310
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
price_missing = {
"detail": [
{
@@ -292,3 +208,87 @@ def test_other_exceptions(client: TestClient):
with patch("json.loads", side_effect=Exception):
response = client.post("/items/", json={"test": "test2"})
assert response.status_code == 400, response.text
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create Item",
+ "operationId": "create_item_items__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001.py b/tests/test_tutorial/test_body_fields/test_tutorial001.py
index fe5a270f3..a7ea0e949 100644
--- a/tests/test_tutorial/test_body_fields/test_tutorial001.py
+++ b/tests/test_tutorial/test_body_fields/test_tutorial001.py
@@ -6,115 +6,6 @@ from docs_src.body_fields.tutorial001 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "put": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Update Item",
- "operationId": "update_item_items__item_id__put",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "integer"},
- "name": "item_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Body_update_item_items__item_id__put"
- }
- }
- },
- "required": True,
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "description": {
- "title": "The description of the item",
- "maxLength": 300,
- "type": "string",
- },
- "price": {
- "title": "Price",
- "exclusiveMinimum": 0.0,
- "type": "number",
- "description": "The price must be greater than zero",
- },
- "tax": {"title": "Tax", "type": "number"},
- },
- },
- "Body_update_item_items__item_id__put": {
- "title": "Body_update_item_items__item_id__put",
- "required": ["item"],
- "type": "object",
- "properties": {"item": {"$ref": "#/components/schemas/Item"}},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
price_not_greater = {
"detail": [
{
@@ -167,3 +58,111 @@ def test(path, body, expected_status, expected_response):
response = client.put(path, json=body)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "integer"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_update_item_items__item_id__put"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {
+ "title": "The description of the item",
+ "maxLength": 300,
+ "type": "string",
+ },
+ "price": {
+ "title": "Price",
+ "exclusiveMinimum": 0.0,
+ "type": "number",
+ "description": "The price must be greater than zero",
+ },
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "Body_update_item_items__item_id__put": {
+ "title": "Body_update_item_items__item_id__put",
+ "required": ["item"],
+ "type": "object",
+ "properties": {"item": {"$ref": "#/components/schemas/Item"}},
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001_an.py b/tests/test_tutorial/test_body_fields/test_tutorial001_an.py
new file mode 100644
index 000000000..32f996ecb
--- /dev/null
+++ b/tests/test_tutorial/test_body_fields/test_tutorial001_an.py
@@ -0,0 +1,168 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from docs_src.body_fields.tutorial001_an import app
+
+client = TestClient(app)
+
+
+price_not_greater = {
+ "detail": [
+ {
+ "ctx": {"limit_value": 0},
+ "loc": ["body", "item", "price"],
+ "msg": "ensure this value is greater than 0",
+ "type": "value_error.number.not_gt",
+ }
+ ]
+}
+
+
+@pytest.mark.parametrize(
+ "path,body,expected_status,expected_response",
+ [
+ (
+ "/items/5",
+ {"item": {"name": "Foo", "price": 3.0}},
+ 200,
+ {
+ "item_id": 5,
+ "item": {"name": "Foo", "price": 3.0, "description": None, "tax": None},
+ },
+ ),
+ (
+ "/items/6",
+ {
+ "item": {
+ "name": "Bar",
+ "price": 0.2,
+ "description": "Some bar",
+ "tax": "5.4",
+ }
+ },
+ 200,
+ {
+ "item_id": 6,
+ "item": {
+ "name": "Bar",
+ "price": 0.2,
+ "description": "Some bar",
+ "tax": 5.4,
+ },
+ },
+ ),
+ ("/items/5", {"item": {"name": "Foo", "price": -3.0}}, 422, price_not_greater),
+ ],
+)
+def test(path, body, expected_status, expected_response):
+ response = client.put(path, json=body)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "integer"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_update_item_items__item_id__put"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {
+ "title": "The description of the item",
+ "maxLength": 300,
+ "type": "string",
+ },
+ "price": {
+ "title": "Price",
+ "exclusiveMinimum": 0.0,
+ "type": "number",
+ "description": "The price must be greater than zero",
+ },
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "Body_update_item_items__item_id__put": {
+ "title": "Body_update_item_items__item_id__put",
+ "required": ["item"],
+ "type": "object",
+ "properties": {"item": {"$ref": "#/components/schemas/Item"}},
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001_an_py310.py b/tests/test_tutorial/test_body_fields/test_tutorial001_an_py310.py
new file mode 100644
index 000000000..20e032fcd
--- /dev/null
+++ b/tests/test_tutorial/test_body_fields/test_tutorial001_an_py310.py
@@ -0,0 +1,176 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.body_fields.tutorial001_an_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+price_not_greater = {
+ "detail": [
+ {
+ "ctx": {"limit_value": 0},
+ "loc": ["body", "item", "price"],
+ "msg": "ensure this value is greater than 0",
+ "type": "value_error.number.not_gt",
+ }
+ ]
+}
+
+
+@needs_py310
+@pytest.mark.parametrize(
+ "path,body,expected_status,expected_response",
+ [
+ (
+ "/items/5",
+ {"item": {"name": "Foo", "price": 3.0}},
+ 200,
+ {
+ "item_id": 5,
+ "item": {"name": "Foo", "price": 3.0, "description": None, "tax": None},
+ },
+ ),
+ (
+ "/items/6",
+ {
+ "item": {
+ "name": "Bar",
+ "price": 0.2,
+ "description": "Some bar",
+ "tax": "5.4",
+ }
+ },
+ 200,
+ {
+ "item_id": 6,
+ "item": {
+ "name": "Bar",
+ "price": 0.2,
+ "description": "Some bar",
+ "tax": 5.4,
+ },
+ },
+ ),
+ ("/items/5", {"item": {"name": "Foo", "price": -3.0}}, 422, price_not_greater),
+ ],
+)
+def test(path, body, expected_status, expected_response, client: TestClient):
+ response = client.put(path, json=body)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "integer"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_update_item_items__item_id__put"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {
+ "title": "The description of the item",
+ "maxLength": 300,
+ "type": "string",
+ },
+ "price": {
+ "title": "Price",
+ "exclusiveMinimum": 0.0,
+ "type": "number",
+ "description": "The price must be greater than zero",
+ },
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "Body_update_item_items__item_id__put": {
+ "title": "Body_update_item_items__item_id__put",
+ "required": ["item"],
+ "type": "object",
+ "properties": {"item": {"$ref": "#/components/schemas/Item"}},
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001_an_py39.py b/tests/test_tutorial/test_body_fields/test_tutorial001_an_py39.py
new file mode 100644
index 000000000..e3baf5f2b
--- /dev/null
+++ b/tests/test_tutorial/test_body_fields/test_tutorial001_an_py39.py
@@ -0,0 +1,176 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.body_fields.tutorial001_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+price_not_greater = {
+ "detail": [
+ {
+ "ctx": {"limit_value": 0},
+ "loc": ["body", "item", "price"],
+ "msg": "ensure this value is greater than 0",
+ "type": "value_error.number.not_gt",
+ }
+ ]
+}
+
+
+@needs_py39
+@pytest.mark.parametrize(
+ "path,body,expected_status,expected_response",
+ [
+ (
+ "/items/5",
+ {"item": {"name": "Foo", "price": 3.0}},
+ 200,
+ {
+ "item_id": 5,
+ "item": {"name": "Foo", "price": 3.0, "description": None, "tax": None},
+ },
+ ),
+ (
+ "/items/6",
+ {
+ "item": {
+ "name": "Bar",
+ "price": 0.2,
+ "description": "Some bar",
+ "tax": "5.4",
+ }
+ },
+ 200,
+ {
+ "item_id": 6,
+ "item": {
+ "name": "Bar",
+ "price": 0.2,
+ "description": "Some bar",
+ "tax": 5.4,
+ },
+ },
+ ),
+ ("/items/5", {"item": {"name": "Foo", "price": -3.0}}, 422, price_not_greater),
+ ],
+)
+def test(path, body, expected_status, expected_response, client: TestClient):
+ response = client.put(path, json=body)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "integer"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_update_item_items__item_id__put"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {
+ "title": "The description of the item",
+ "maxLength": 300,
+ "type": "string",
+ },
+ "price": {
+ "title": "Price",
+ "exclusiveMinimum": 0.0,
+ "type": "number",
+ "description": "The price must be greater than zero",
+ },
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "Body_update_item_items__item_id__put": {
+ "title": "Body_update_item_items__item_id__put",
+ "required": ["item"],
+ "type": "object",
+ "properties": {"item": {"$ref": "#/components/schemas/Item"}},
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py b/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py
index 993e2a91d..4c2f48674 100644
--- a/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py
@@ -3,108 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py310
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "put": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Update Item",
- "operationId": "update_item_items__item_id__put",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "integer"},
- "name": "item_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Body_update_item_items__item_id__put"
- }
- }
- },
- "required": True,
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "description": {
- "title": "The description of the item",
- "maxLength": 300,
- "type": "string",
- },
- "price": {
- "title": "Price",
- "exclusiveMinimum": 0.0,
- "type": "number",
- "description": "The price must be greater than zero",
- },
- "tax": {"title": "Tax", "type": "number"},
- },
- },
- "Body_update_item_items__item_id__put": {
- "title": "Body_update_item_items__item_id__put",
- "required": ["item"],
- "type": "object",
- "properties": {"item": {"$ref": "#/components/schemas/Item"}},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -114,13 +12,6 @@ def get_client():
return client
-@needs_py310
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
price_not_greater = {
"detail": [
{
@@ -174,3 +65,112 @@ def test(path, body, expected_status, expected_response, client: TestClient):
response = client.put(path, json=body)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "integer"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_update_item_items__item_id__put"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {
+ "title": "The description of the item",
+ "maxLength": 300,
+ "type": "string",
+ },
+ "price": {
+ "title": "Price",
+ "exclusiveMinimum": 0.0,
+ "type": "number",
+ "description": "The price must be greater than zero",
+ },
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "Body_update_item_items__item_id__put": {
+ "title": "Body_update_item_items__item_id__put",
+ "required": ["item"],
+ "type": "object",
+ "properties": {"item": {"$ref": "#/components/schemas/Item"}},
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py
index 8dc710d75..496ab38fb 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py
@@ -5,107 +5,6 @@ from docs_src.body_multiple_params.tutorial001 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "put": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Update Item",
- "operationId": "update_item_items__item_id__put",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "The ID of the item to get",
- "maximum": 1000.0,
- "minimum": 0.0,
- "type": "integer",
- },
- "name": "item_id",
- "in": "path",
- },
- {
- "required": False,
- "schema": {"title": "Q", "type": "string"},
- "name": "q",
- "in": "query",
- },
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- }
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- "description": {"title": "Description", "type": "string"},
- "tax": {"title": "Tax", "type": "number"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
item_id_not_int = {
"detail": [
@@ -145,3 +44,104 @@ def test_post_body(path, body, expected_status, expected_response):
response = client.put(path, json=body)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "The ID of the item to get",
+ "maximum": 1000.0,
+ "minimum": 0.0,
+ "type": "integer",
+ },
+ "name": "item_id",
+ "in": "path",
+ },
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ }
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an.py
new file mode 100644
index 000000000..74a8a9b2e
--- /dev/null
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an.py
@@ -0,0 +1,147 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from docs_src.body_multiple_params.tutorial001_an import app
+
+client = TestClient(app)
+
+
+item_id_not_int = {
+ "detail": [
+ {
+ "loc": ["path", "item_id"],
+ "msg": "value is not a valid integer",
+ "type": "type_error.integer",
+ }
+ ]
+}
+
+
+@pytest.mark.parametrize(
+ "path,body,expected_status,expected_response",
+ [
+ (
+ "/items/5?q=bar",
+ {"name": "Foo", "price": 50.5},
+ 200,
+ {
+ "item_id": 5,
+ "item": {
+ "name": "Foo",
+ "price": 50.5,
+ "description": None,
+ "tax": None,
+ },
+ "q": "bar",
+ },
+ ),
+ ("/items/5?q=bar", None, 200, {"item_id": 5, "q": "bar"}),
+ ("/items/5", None, 200, {"item_id": 5}),
+ ("/items/foo", None, 422, item_id_not_int),
+ ],
+)
+def test_post_body(path, body, expected_status, expected_response):
+ response = client.put(path, json=body)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "The ID of the item to get",
+ "maximum": 1000.0,
+ "minimum": 0.0,
+ "type": "integer",
+ },
+ "name": "item_id",
+ "in": "path",
+ },
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ }
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py310.py
new file mode 100644
index 000000000..9c764b6d1
--- /dev/null
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py310.py
@@ -0,0 +1,155 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.body_multiple_params.tutorial001_an_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+item_id_not_int = {
+ "detail": [
+ {
+ "loc": ["path", "item_id"],
+ "msg": "value is not a valid integer",
+ "type": "type_error.integer",
+ }
+ ]
+}
+
+
+@needs_py310
+@pytest.mark.parametrize(
+ "path,body,expected_status,expected_response",
+ [
+ (
+ "/items/5?q=bar",
+ {"name": "Foo", "price": 50.5},
+ 200,
+ {
+ "item_id": 5,
+ "item": {
+ "name": "Foo",
+ "price": 50.5,
+ "description": None,
+ "tax": None,
+ },
+ "q": "bar",
+ },
+ ),
+ ("/items/5?q=bar", None, 200, {"item_id": 5, "q": "bar"}),
+ ("/items/5", None, 200, {"item_id": 5}),
+ ("/items/foo", None, 422, item_id_not_int),
+ ],
+)
+def test_post_body(path, body, expected_status, expected_response, client: TestClient):
+ response = client.put(path, json=body)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "The ID of the item to get",
+ "maximum": 1000.0,
+ "minimum": 0.0,
+ "type": "integer",
+ },
+ "name": "item_id",
+ "in": "path",
+ },
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ }
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py39.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py39.py
new file mode 100644
index 000000000..0cca29433
--- /dev/null
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py39.py
@@ -0,0 +1,155 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.body_multiple_params.tutorial001_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+item_id_not_int = {
+ "detail": [
+ {
+ "loc": ["path", "item_id"],
+ "msg": "value is not a valid integer",
+ "type": "type_error.integer",
+ }
+ ]
+}
+
+
+@needs_py39
+@pytest.mark.parametrize(
+ "path,body,expected_status,expected_response",
+ [
+ (
+ "/items/5?q=bar",
+ {"name": "Foo", "price": 50.5},
+ 200,
+ {
+ "item_id": 5,
+ "item": {
+ "name": "Foo",
+ "price": 50.5,
+ "description": None,
+ "tax": None,
+ },
+ "q": "bar",
+ },
+ ),
+ ("/items/5?q=bar", None, 200, {"item_id": 5, "q": "bar"}),
+ ("/items/5", None, 200, {"item_id": 5}),
+ ("/items/foo", None, 422, item_id_not_int),
+ ],
+)
+def test_post_body(path, body, expected_status, expected_response, client: TestClient):
+ response = client.put(path, json=body)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "The ID of the item to get",
+ "maximum": 1000.0,
+ "minimum": 0.0,
+ "type": "integer",
+ },
+ "name": "item_id",
+ "in": "path",
+ },
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ }
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py
index 5114ccea2..3b61e717e 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py
@@ -3,101 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py310
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "put": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Update Item",
- "operationId": "update_item_items__item_id__put",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "The ID of the item to get",
- "maximum": 1000.0,
- "minimum": 0.0,
- "type": "integer",
- },
- "name": "item_id",
- "in": "path",
- },
- {
- "required": False,
- "schema": {"title": "Q", "type": "string"},
- "name": "q",
- "in": "query",
- },
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- }
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- "description": {"title": "Description", "type": "string"},
- "tax": {"title": "Tax", "type": "number"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -107,13 +12,6 @@ def get_client():
return client
-@needs_py310
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
item_id_not_int = {
"detail": [
{
@@ -153,3 +51,105 @@ def test_post_body(path, body, expected_status, expected_response, client: TestC
response = client.put(path, json=body)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "The ID of the item to get",
+ "maximum": 1000.0,
+ "minimum": 0.0,
+ "type": "integer",
+ },
+ "name": "item_id",
+ "in": "path",
+ },
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ }
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py
index 64aa9c43b..b34377a28 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py
@@ -5,118 +5,6 @@ from docs_src.body_multiple_params.tutorial003 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "put": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Update Item",
- "operationId": "update_item_items__item_id__put",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "integer"},
- "name": "item_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Body_update_item_items__item_id__put"
- }
- }
- },
- "required": True,
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- "description": {"title": "Description", "type": "string"},
- "tax": {"title": "Tax", "type": "number"},
- },
- },
- "User": {
- "title": "User",
- "required": ["username"],
- "type": "object",
- "properties": {
- "username": {"title": "Username", "type": "string"},
- "full_name": {"title": "Full Name", "type": "string"},
- },
- },
- "Body_update_item_items__item_id__put": {
- "title": "Body_update_item_items__item_id__put",
- "required": ["item", "user", "importance"],
- "type": "object",
- "properties": {
- "item": {"$ref": "#/components/schemas/Item"},
- "user": {"$ref": "#/components/schemas/User"},
- "importance": {"title": "Importance", "type": "integer"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
# Test required and embedded body parameters with no bodies sent
@pytest.mark.parametrize(
@@ -196,3 +84,115 @@ def test_post_body(path, body, expected_status, expected_response):
response = client.put(path, json=body)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "integer"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_update_item_items__item_id__put"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "User": {
+ "title": "User",
+ "required": ["username"],
+ "type": "object",
+ "properties": {
+ "username": {"title": "Username", "type": "string"},
+ "full_name": {"title": "Full Name", "type": "string"},
+ },
+ },
+ "Body_update_item_items__item_id__put": {
+ "title": "Body_update_item_items__item_id__put",
+ "required": ["item", "user", "importance"],
+ "type": "object",
+ "properties": {
+ "item": {"$ref": "#/components/schemas/Item"},
+ "user": {"$ref": "#/components/schemas/User"},
+ "importance": {"title": "Importance", "type": "integer"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an.py
new file mode 100644
index 000000000..9b8d5e15b
--- /dev/null
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an.py
@@ -0,0 +1,198 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from docs_src.body_multiple_params.tutorial003_an import app
+
+client = TestClient(app)
+
+
+# Test required and embedded body parameters with no bodies sent
+@pytest.mark.parametrize(
+ "path,body,expected_status,expected_response",
+ [
+ (
+ "/items/5",
+ {
+ "importance": 2,
+ "item": {"name": "Foo", "price": 50.5},
+ "user": {"username": "Dave"},
+ },
+ 200,
+ {
+ "item_id": 5,
+ "importance": 2,
+ "item": {
+ "name": "Foo",
+ "price": 50.5,
+ "description": None,
+ "tax": None,
+ },
+ "user": {"username": "Dave", "full_name": None},
+ },
+ ),
+ (
+ "/items/5",
+ None,
+ 422,
+ {
+ "detail": [
+ {
+ "loc": ["body", "item"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["body", "user"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["body", "importance"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ ]
+ },
+ ),
+ (
+ "/items/5",
+ [],
+ 422,
+ {
+ "detail": [
+ {
+ "loc": ["body", "item"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["body", "user"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["body", "importance"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ ]
+ },
+ ),
+ ],
+)
+def test_post_body(path, body, expected_status, expected_response):
+ response = client.put(path, json=body)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "integer"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_update_item_items__item_id__put"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "User": {
+ "title": "User",
+ "required": ["username"],
+ "type": "object",
+ "properties": {
+ "username": {"title": "Username", "type": "string"},
+ "full_name": {"title": "Full Name", "type": "string"},
+ },
+ },
+ "Body_update_item_items__item_id__put": {
+ "title": "Body_update_item_items__item_id__put",
+ "required": ["item", "user", "importance"],
+ "type": "object",
+ "properties": {
+ "item": {"$ref": "#/components/schemas/Item"},
+ "user": {"$ref": "#/components/schemas/User"},
+ "importance": {"title": "Importance", "type": "integer"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py310.py
new file mode 100644
index 000000000..f8af555fc
--- /dev/null
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py310.py
@@ -0,0 +1,206 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.body_multiple_params.tutorial003_an_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+# Test required and embedded body parameters with no bodies sent
+@needs_py310
+@pytest.mark.parametrize(
+ "path,body,expected_status,expected_response",
+ [
+ (
+ "/items/5",
+ {
+ "importance": 2,
+ "item": {"name": "Foo", "price": 50.5},
+ "user": {"username": "Dave"},
+ },
+ 200,
+ {
+ "item_id": 5,
+ "importance": 2,
+ "item": {
+ "name": "Foo",
+ "price": 50.5,
+ "description": None,
+ "tax": None,
+ },
+ "user": {"username": "Dave", "full_name": None},
+ },
+ ),
+ (
+ "/items/5",
+ None,
+ 422,
+ {
+ "detail": [
+ {
+ "loc": ["body", "item"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["body", "user"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["body", "importance"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ ]
+ },
+ ),
+ (
+ "/items/5",
+ [],
+ 422,
+ {
+ "detail": [
+ {
+ "loc": ["body", "item"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["body", "user"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["body", "importance"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ ]
+ },
+ ),
+ ],
+)
+def test_post_body(path, body, expected_status, expected_response, client: TestClient):
+ response = client.put(path, json=body)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "integer"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_update_item_items__item_id__put"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "User": {
+ "title": "User",
+ "required": ["username"],
+ "type": "object",
+ "properties": {
+ "username": {"title": "Username", "type": "string"},
+ "full_name": {"title": "Full Name", "type": "string"},
+ },
+ },
+ "Body_update_item_items__item_id__put": {
+ "title": "Body_update_item_items__item_id__put",
+ "required": ["item", "user", "importance"],
+ "type": "object",
+ "properties": {
+ "item": {"$ref": "#/components/schemas/Item"},
+ "user": {"$ref": "#/components/schemas/User"},
+ "importance": {"title": "Importance", "type": "integer"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py39.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py39.py
new file mode 100644
index 000000000..06e2c3146
--- /dev/null
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py39.py
@@ -0,0 +1,206 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.body_multiple_params.tutorial003_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+# Test required and embedded body parameters with no bodies sent
+@needs_py39
+@pytest.mark.parametrize(
+ "path,body,expected_status,expected_response",
+ [
+ (
+ "/items/5",
+ {
+ "importance": 2,
+ "item": {"name": "Foo", "price": 50.5},
+ "user": {"username": "Dave"},
+ },
+ 200,
+ {
+ "item_id": 5,
+ "importance": 2,
+ "item": {
+ "name": "Foo",
+ "price": 50.5,
+ "description": None,
+ "tax": None,
+ },
+ "user": {"username": "Dave", "full_name": None},
+ },
+ ),
+ (
+ "/items/5",
+ None,
+ 422,
+ {
+ "detail": [
+ {
+ "loc": ["body", "item"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["body", "user"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["body", "importance"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ ]
+ },
+ ),
+ (
+ "/items/5",
+ [],
+ 422,
+ {
+ "detail": [
+ {
+ "loc": ["body", "item"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["body", "user"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["body", "importance"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ ]
+ },
+ ),
+ ],
+)
+def test_post_body(path, body, expected_status, expected_response, client: TestClient):
+ response = client.put(path, json=body)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "integer"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_update_item_items__item_id__put"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "User": {
+ "title": "User",
+ "required": ["username"],
+ "type": "object",
+ "properties": {
+ "username": {"title": "Username", "type": "string"},
+ "full_name": {"title": "Full Name", "type": "string"},
+ },
+ },
+ "Body_update_item_items__item_id__put": {
+ "title": "Body_update_item_items__item_id__put",
+ "required": ["item", "user", "importance"],
+ "type": "object",
+ "properties": {
+ "item": {"$ref": "#/components/schemas/Item"},
+ "user": {"$ref": "#/components/schemas/User"},
+ "importance": {"title": "Importance", "type": "integer"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py
index fc019d8bb..82c5fb101 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py
@@ -3,112 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py310
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "put": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Update Item",
- "operationId": "update_item_items__item_id__put",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "integer"},
- "name": "item_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Body_update_item_items__item_id__put"
- }
- }
- },
- "required": True,
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- "description": {"title": "Description", "type": "string"},
- "tax": {"title": "Tax", "type": "number"},
- },
- },
- "User": {
- "title": "User",
- "required": ["username"],
- "type": "object",
- "properties": {
- "username": {"title": "Username", "type": "string"},
- "full_name": {"title": "Full Name", "type": "string"},
- },
- },
- "Body_update_item_items__item_id__put": {
- "title": "Body_update_item_items__item_id__put",
- "required": ["item", "user", "importance"],
- "type": "object",
- "properties": {
- "item": {"$ref": "#/components/schemas/Item"},
- "user": {"$ref": "#/components/schemas/User"},
- "importance": {"title": "Importance", "type": "integer"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -118,13 +12,6 @@ def get_client():
return client
-@needs_py310
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
# Test required and embedded body parameters with no bodies sent
@needs_py310
@pytest.mark.parametrize(
@@ -204,3 +91,116 @@ def test_post_body(path, body, expected_status, expected_response, client: TestC
response = client.put(path, json=body)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "integer"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_update_item_items__item_id__put"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "User": {
+ "title": "User",
+ "required": ["username"],
+ "type": "object",
+ "properties": {
+ "username": {"title": "Username", "type": "string"},
+ "full_name": {"title": "Full Name", "type": "string"},
+ },
+ },
+ "Body_update_item_items__item_id__put": {
+ "title": "Body_update_item_items__item_id__put",
+ "required": ["item", "user", "importance"],
+ "type": "object",
+ "properties": {
+ "item": {"$ref": "#/components/schemas/Item"},
+ "user": {"$ref": "#/components/schemas/User"},
+ "importance": {"title": "Importance", "type": "integer"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py
index c56d41b5b..378c24197 100644
--- a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py
+++ b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py
@@ -4,82 +4,6 @@ from docs_src.body_nested_models.tutorial009 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/index-weights/": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Create Index Weights",
- "operationId": "create_index_weights_index_weights__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "title": "Weights",
- "type": "object",
- "additionalProperties": {"type": "number"},
- }
- }
- },
- "required": True,
- },
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_post_body():
data = {"2": 2.2, "3": 3.3}
@@ -101,3 +25,79 @@ def test_post_invalid_body():
}
]
}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/index-weights/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create Index Weights",
+ "operationId": "create_index_weights_index_weights__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Weights",
+ "type": "object",
+ "additionalProperties": {"type": "number"},
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py b/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py
index 5b8d82861..5ca63a92b 100644
--- a/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py
+++ b/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py
@@ -3,76 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py39
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/index-weights/": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Create Index Weights",
- "operationId": "create_index_weights_index_weights__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "title": "Weights",
- "type": "object",
- "additionalProperties": {"type": "number"},
- }
- }
- },
- "required": True,
- },
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -82,13 +12,6 @@ def get_client():
return client
-@needs_py39
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
@needs_py39
def test_post_body(client: TestClient):
data = {"2": 2.2, "3": 3.3}
@@ -111,3 +34,80 @@ def test_post_invalid_body(client: TestClient):
}
]
}
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/index-weights/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create Index Weights",
+ "operationId": "create_index_weights_index_weights__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Weights",
+ "type": "object",
+ "additionalProperties": {"type": "number"},
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001.py b/tests/test_tutorial/test_body_updates/test_tutorial001.py
index efd0e4676..939bf44e0 100644
--- a/tests/test_tutorial/test_body_updates/test_tutorial001.py
+++ b/tests/test_tutorial/test_body_updates/test_tutorial001.py
@@ -4,138 +4,6 @@ from docs_src.body_updates.tutorial001 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Item",
- "operationId": "read_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- },
- "put": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Update Item",
- "operationId": "update_item_items__item_id__put",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
- },
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "description": {"title": "Description", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- "tax": {"title": "Tax", "type": "number", "default": 10.5},
- "tags": {
- "title": "Tags",
- "type": "array",
- "items": {"type": "string"},
- "default": [],
- },
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get():
response = client.get("/items/baz")
@@ -160,3 +28,135 @@ def test_put():
"tax": 10.5,
"tags": [],
}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ },
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ "required": True,
+ },
+ },
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "tax": {"title": "Tax", "type": "number", "default": 10.5},
+ "tags": {
+ "title": "Tags",
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py b/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py
index 49279b320..5f50f2071 100644
--- a/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py
@@ -3,132 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py310
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Item",
- "operationId": "read_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- },
- "put": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Update Item",
- "operationId": "update_item_items__item_id__put",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
- },
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "description": {"title": "Description", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- "tax": {"title": "Tax", "type": "number", "default": 10.5},
- "tags": {
- "title": "Tags",
- "type": "array",
- "items": {"type": "string"},
- "default": [],
- },
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -138,13 +12,6 @@ def get_client():
return client
-@needs_py310
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
@needs_py310
def test_get(client: TestClient):
response = client.get("/items/baz")
@@ -170,3 +37,136 @@ def test_put(client: TestClient):
"tax": 10.5,
"tags": [],
}
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ },
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ "required": True,
+ },
+ },
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "tax": {"title": "Tax", "type": "number", "default": 10.5},
+ "tags": {
+ "title": "Tags",
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py b/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py
index 872530bcf..d4fdabce6 100644
--- a/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py
+++ b/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py
@@ -3,132 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py39
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Item",
- "operationId": "read_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- },
- "put": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Update Item",
- "operationId": "update_item_items__item_id__put",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
- },
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "description": {"title": "Description", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- "tax": {"title": "Tax", "type": "number", "default": 10.5},
- "tags": {
- "title": "Tags",
- "type": "array",
- "items": {"type": "string"},
- "default": [],
- },
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -138,13 +12,6 @@ def get_client():
return client
-@needs_py39
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
@needs_py39
def test_get(client: TestClient):
response = client.get("/items/baz")
@@ -170,3 +37,136 @@ def test_put(client: TestClient):
"tax": 10.5,
"tags": [],
}
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ },
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Update Item",
+ "operationId": "update_item_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ "required": True,
+ },
+ },
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "tax": {"title": "Tax", "type": "number", "default": 10.5},
+ "tags": {
+ "title": "Tags",
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py b/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py
index 93c8775ce..c1d8fd805 100644
--- a/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py
+++ b/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py
@@ -4,35 +4,6 @@ from fastapi.testclient import TestClient
from docs_src.conditional_openapi import tutorial001
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/": {
- "get": {
- "summary": "Root",
- "operationId": "root__get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- }
- }
- },
-}
-
-
-def test_default_openapi():
- client = TestClient(tutorial001.app)
- response = client.get("/openapi.json")
- assert response.json() == openapi_schema
- response = client.get("/docs")
- assert response.status_code == 200, response.text
- response = client.get("/redoc")
- assert response.status_code == 200, response.text
-
def test_disable_openapi(monkeypatch):
monkeypatch.setenv("OPENAPI_URL", "")
@@ -51,3 +22,31 @@ def test_root():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message": "Hello World"}
+
+
+def test_default_openapi():
+ importlib.reload(tutorial001)
+ client = TestClient(tutorial001.app)
+ response = client.get("/docs")
+ assert response.status_code == 200, response.text
+ response = client.get("/redoc")
+ assert response.status_code == 200, response.text
+ response = client.get("/openapi.json")
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/": {
+ "get": {
+ "summary": "Root",
+ "operationId": "root__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001.py b/tests/test_tutorial/test_cookie_params/test_tutorial001.py
index 38ae211db..c3511d129 100644
--- a/tests/test_tutorial/test_cookie_params/test_tutorial001.py
+++ b/tests/test_tutorial/test_cookie_params/test_tutorial001.py
@@ -3,77 +3,10 @@ from fastapi.testclient import TestClient
from docs_src.cookie_params.tutorial001 import app
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Ads Id", "type": "string"},
- "name": "ads_id",
- "in": "cookie",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.mark.parametrize(
"path,cookies,expected_status,expected_response",
[
- ("/openapi.json", None, 200, openapi_schema),
("/items", None, 200, {"ads_id": None}),
("/items", {"ads_id": "ads_track"}, 200, {"ads_id": "ads_track"}),
(
@@ -90,3 +23,76 @@ def test(path, cookies, expected_status, expected_response):
response = client.get(path)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Ads Id", "type": "string"},
+ "name": "ads_id",
+ "in": "cookie",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001_an.py b/tests/test_tutorial/test_cookie_params/test_tutorial001_an.py
new file mode 100644
index 000000000..f4f94c09d
--- /dev/null
+++ b/tests/test_tutorial/test_cookie_params/test_tutorial001_an.py
@@ -0,0 +1,98 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from docs_src.cookie_params.tutorial001_an import app
+
+
+@pytest.mark.parametrize(
+ "path,cookies,expected_status,expected_response",
+ [
+ ("/items", None, 200, {"ads_id": None}),
+ ("/items", {"ads_id": "ads_track"}, 200, {"ads_id": "ads_track"}),
+ (
+ "/items",
+ {"ads_id": "ads_track", "session": "cookiesession"},
+ 200,
+ {"ads_id": "ads_track"},
+ ),
+ ("/items", {"session": "cookiesession"}, 200, {"ads_id": None}),
+ ],
+)
+def test(path, cookies, expected_status, expected_response):
+ client = TestClient(app, cookies=cookies)
+ response = client.get(path)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Ads Id", "type": "string"},
+ "name": "ads_id",
+ "in": "cookie",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001_an_py310.py b/tests/test_tutorial/test_cookie_params/test_tutorial001_an_py310.py
new file mode 100644
index 000000000..a80f10f81
--- /dev/null
+++ b/tests/test_tutorial/test_cookie_params/test_tutorial001_an_py310.py
@@ -0,0 +1,104 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@needs_py310
+@pytest.mark.parametrize(
+ "path,cookies,expected_status,expected_response",
+ [
+ ("/items", None, 200, {"ads_id": None}),
+ ("/items", {"ads_id": "ads_track"}, 200, {"ads_id": "ads_track"}),
+ (
+ "/items",
+ {"ads_id": "ads_track", "session": "cookiesession"},
+ 200,
+ {"ads_id": "ads_track"},
+ ),
+ ("/items", {"session": "cookiesession"}, 200, {"ads_id": None}),
+ ],
+)
+def test(path, cookies, expected_status, expected_response):
+ from docs_src.cookie_params.tutorial001_an_py310 import app
+
+ client = TestClient(app, cookies=cookies)
+ response = client.get(path)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema():
+ from docs_src.cookie_params.tutorial001_an_py310 import app
+
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Ads Id", "type": "string"},
+ "name": "ads_id",
+ "in": "cookie",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001_an_py39.py b/tests/test_tutorial/test_cookie_params/test_tutorial001_an_py39.py
new file mode 100644
index 000000000..1be898c09
--- /dev/null
+++ b/tests/test_tutorial/test_cookie_params/test_tutorial001_an_py39.py
@@ -0,0 +1,104 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@needs_py39
+@pytest.mark.parametrize(
+ "path,cookies,expected_status,expected_response",
+ [
+ ("/items", None, 200, {"ads_id": None}),
+ ("/items", {"ads_id": "ads_track"}, 200, {"ads_id": "ads_track"}),
+ (
+ "/items",
+ {"ads_id": "ads_track", "session": "cookiesession"},
+ 200,
+ {"ads_id": "ads_track"},
+ ),
+ ("/items", {"session": "cookiesession"}, 200, {"ads_id": None}),
+ ],
+)
+def test(path, cookies, expected_status, expected_response):
+ from docs_src.cookie_params.tutorial001_an_py39 import app
+
+ client = TestClient(app, cookies=cookies)
+ response = client.get(path)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py39
+def test_openapi_schema():
+ from docs_src.cookie_params.tutorial001_an_py39 import app
+
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Ads Id", "type": "string"},
+ "name": "ads_id",
+ "in": "cookie",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py b/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py
index 5ad52fb5e..7ba542c90 100644
--- a/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py
@@ -3,78 +3,11 @@ from fastapi.testclient import TestClient
from ...utils import needs_py310
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Ads Id", "type": "string"},
- "name": "ads_id",
- "in": "cookie",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@needs_py310
@pytest.mark.parametrize(
"path,cookies,expected_status,expected_response",
[
- ("/openapi.json", None, 200, openapi_schema),
("/items", None, 200, {"ads_id": None}),
("/items", {"ads_id": "ads_track"}, 200, {"ads_id": "ads_track"}),
(
@@ -93,3 +26,79 @@ def test(path, cookies, expected_status, expected_response):
response = client.get(path)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema():
+ from docs_src.cookie_params.tutorial001_py310 import app
+
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Ads Id", "type": "string"},
+ "name": "ads_id",
+ "in": "cookie",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial001.py b/tests/test_tutorial/test_custom_response/test_tutorial001.py
index 430076f88..da2ca8d62 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial001.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial001.py
@@ -4,33 +4,31 @@ from docs_src.custom_response.tutorial001 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get_custom_response():
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.json() == [{"item_id": "Foo"}]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial001b.py b/tests/test_tutorial/test_custom_response/test_tutorial001b.py
index 0f15d5f48..f681f5a9d 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial001b.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial001b.py
@@ -4,33 +4,31 @@ from docs_src.custom_response.tutorial001b import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get_custom_response():
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.json() == [{"item_id": "Foo"}]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial004.py b/tests/test_tutorial/test_custom_response/test_tutorial004.py
index 5d75cce96..ef0ba3446 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial004.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial004.py
@@ -4,24 +4,6 @@ from docs_src.custom_response.tutorial004 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"text/html": {"schema": {"type": "string"}}},
- }
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- }
- }
- },
-}
html_contents = """
@@ -35,13 +17,30 @@ html_contents = """
"""
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
def test_get_custom_response():
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.text == html_contents
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"text/html": {"schema": {"type": "string"}}},
+ }
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial005.py b/tests/test_tutorial/test_custom_response/test_tutorial005.py
index ecf6ee2b9..e4b5c1546 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial005.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial005.py
@@ -4,33 +4,31 @@ from docs_src.custom_response.tutorial005 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/": {
- "get": {
- "summary": "Main",
- "operationId": "main__get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"text/plain": {"schema": {"type": "string"}}},
- }
- },
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get():
response = client.get("/")
assert response.status_code == 200, response.text
assert response.text == "Hello World"
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/": {
+ "get": {
+ "summary": "Main",
+ "operationId": "main__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"text/plain": {"schema": {"type": "string"}}},
+ }
+ },
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006.py b/tests/test_tutorial/test_custom_response/test_tutorial006.py
index 9b10916e5..9f1b07bee 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial006.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial006.py
@@ -5,33 +5,30 @@ from docs_src.custom_response.tutorial006 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/typer": {
- "get": {
- "summary": "Redirect Typer",
- "operationId": "redirect_typer_typer_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- }
- }
- },
-}
+def test_get():
+ response = client.get("/typer", follow_redirects=False)
+ assert response.status_code == 307, response.text
+ assert response.headers["location"] == "https://typer.tiangolo.com"
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
-def test_get():
- response = client.get("/typer", follow_redirects=False)
- assert response.status_code == 307, response.text
- assert response.headers["location"] == "https://typer.tiangolo.com"
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/typer": {
+ "get": {
+ "summary": "Redirect Typer",
+ "operationId": "redirect_typer_typer_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006b.py b/tests/test_tutorial/test_custom_response/test_tutorial006b.py
index b3e60e86a..cf204cbc0 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial006b.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial006b.py
@@ -5,28 +5,25 @@ from docs_src.custom_response.tutorial006b import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/fastapi": {
- "get": {
- "summary": "Redirect Fastapi",
- "operationId": "redirect_fastapi_fastapi_get",
- "responses": {"307": {"description": "Successful Response"}},
- }
- }
- },
-}
+def test_redirect_response_class():
+ response = client.get("/fastapi", follow_redirects=False)
+ assert response.status_code == 307
+ assert response.headers["location"] == "https://fastapi.tiangolo.com"
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
-def test_redirect_response_class():
- response = client.get("/fastapi", follow_redirects=False)
- assert response.status_code == 307
- assert response.headers["location"] == "https://fastapi.tiangolo.com"
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/fastapi": {
+ "get": {
+ "summary": "Redirect Fastapi",
+ "operationId": "redirect_fastapi_fastapi_get",
+ "responses": {"307": {"description": "Successful Response"}},
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006c.py b/tests/test_tutorial/test_custom_response/test_tutorial006c.py
index 0cb6ddaa3..f196899ac 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial006c.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial006c.py
@@ -5,28 +5,25 @@ from docs_src.custom_response.tutorial006c import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/pydantic": {
- "get": {
- "summary": "Redirect Pydantic",
- "operationId": "redirect_pydantic_pydantic_get",
- "responses": {"302": {"description": "Successful Response"}},
- }
- }
- },
-}
+def test_redirect_status_code():
+ response = client.get("/pydantic", follow_redirects=False)
+ assert response.status_code == 302
+ assert response.headers["location"] == "https://pydantic-docs.helpmanual.io/"
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
-def test_redirect_status_code():
- response = client.get("/pydantic", follow_redirects=False)
- assert response.status_code == 302
- assert response.headers["location"] == "https://pydantic-docs.helpmanual.io/"
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/pydantic": {
+ "get": {
+ "summary": "Redirect Pydantic",
+ "operationId": "redirect_pydantic_pydantic_get",
+ "responses": {"302": {"description": "Successful Response"}},
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dataclasses/__init__.py b/tests/test_tutorial/test_dataclasses/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial001.py b/tests/test_tutorial/test_dataclasses/test_tutorial001.py
index bf1564194..26ae04c51 100644
--- a/tests/test_tutorial/test_dataclasses/test_tutorial001.py
+++ b/tests/test_tutorial/test_dataclasses/test_tutorial001.py
@@ -4,89 +4,6 @@ from docs_src.dataclasses.tutorial001 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "post": {
- "summary": "Create Item",
- "operationId": "create_item_items__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "Item": {
- "title": "Item",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- "description": {"title": "Description", "type": "string"},
- "tax": {"title": "Tax", "type": "number"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200
- assert response.json() == openapi_schema
-
def test_post_item():
response = client.post("/items/", json={"name": "Foo", "price": 3})
@@ -111,3 +28,86 @@ def test_post_invalid_item():
}
]
}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "post": {
+ "summary": "Create Item",
+ "operationId": "create_item_items__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial002.py b/tests/test_tutorial/test_dataclasses/test_tutorial002.py
index 34aeb0be5..675e826b1 100644
--- a/tests/test_tutorial/test_dataclasses/test_tutorial002.py
+++ b/tests/test_tutorial/test_dataclasses/test_tutorial002.py
@@ -1,71 +1,9 @@
-from copy import deepcopy
-
from fastapi.testclient import TestClient
from docs_src.dataclasses.tutorial002 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/next": {
- "get": {
- "summary": "Read Next Item",
- "operationId": "read_next_item_items_next_get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- }
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- "tags": {
- "title": "Tags",
- "type": "array",
- "items": {"type": "string"},
- },
- "description": {"title": "Description", "type": "string"},
- "tax": {"title": "Tax", "type": "number"},
- },
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200
- # TODO: remove this once Pydantic 1.9 is released
- # Ref: https://github.com/samuelcolvin/pydantic/pull/2557
- data = response.json()
- alternative_data1 = deepcopy(data)
- alternative_data2 = deepcopy(data)
- alternative_data1["components"]["schemas"]["Item"]["required"] = ["name", "price"]
- alternative_data2["components"]["schemas"]["Item"]["required"] = [
- "name",
- "price",
- "tags",
- ]
- assert alternative_data1 == openapi_schema or alternative_data2 == openapi_schema
-
def test_get_item():
response = client.get("/items/next")
@@ -77,3 +15,51 @@ def test_get_item():
"tags": ["breater"],
"tax": None,
}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ data = response.json()
+ assert data == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/next": {
+ "get": {
+ "summary": "Read Next Item",
+ "operationId": "read_next_item_items_next_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ }
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "tags": {
+ "title": "Tags",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ },
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial003.py b/tests/test_tutorial/test_dataclasses/test_tutorial003.py
index 2d86f7b9a..f3378fe62 100644
--- a/tests/test_tutorial/test_dataclasses/test_tutorial003.py
+++ b/tests/test_tutorial/test_dataclasses/test_tutorial003.py
@@ -4,136 +4,6 @@ from docs_src.dataclasses.tutorial003 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/authors/{author_id}/items/": {
- "post": {
- "summary": "Create Author Items",
- "operationId": "create_author_items_authors__author_id__items__post",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Author Id", "type": "string"},
- "name": "author_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "title": "Items",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Item"},
- }
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Author"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- "/authors/": {
- "get": {
- "summary": "Get Authors",
- "operationId": "get_authors_authors__get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Get Authors Authors Get",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Author"},
- }
- }
- },
- }
- },
- }
- },
- },
- "components": {
- "schemas": {
- "Author": {
- "title": "Author",
- "required": ["name"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "items": {
- "title": "Items",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Item"},
- },
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "Item": {
- "title": "Item",
- "required": ["name"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "description": {"title": "Description", "type": "string"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200
- assert response.json() == openapi_schema
-
def test_post_authors_item():
response = client.post(
@@ -179,3 +49,135 @@ def test_get_authors():
],
},
]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/authors/{author_id}/items/": {
+ "post": {
+ "summary": "Create Author Items",
+ "operationId": "create_author_items_authors__author_id__items__post",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Author Id", "type": "string"},
+ "name": "author_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Items",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Author"}
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/authors/": {
+ "get": {
+ "summary": "Get Authors",
+ "operationId": "get_authors_authors__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Get Authors Authors Get",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Author"
+ },
+ }
+ }
+ },
+ }
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Author": {
+ "title": "Author",
+ "required": ["name"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "items": {
+ "title": "Items",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ },
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "Item": {
+ "title": "Item",
+ "required": ["name"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001.py b/tests/test_tutorial/test_dependencies/test_tutorial001.py
index c3bca5d5b..974b9304f 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial001.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial001.py
@@ -5,132 +5,6 @@ from docs_src.dependencies.tutorial001 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Q", "type": "string"},
- "name": "q",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Skip", "type": "integer", "default": 0},
- "name": "skip",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Limit", "type": "integer", "default": 100},
- "name": "limit",
- "in": "query",
- },
- ],
- }
- },
- "/users/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Users",
- "operationId": "read_users_users__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Q", "type": "string"},
- "name": "q",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Skip", "type": "integer", "default": 0},
- "name": "skip",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Limit", "type": "integer", "default": 100},
- "name": "limit",
- "in": "query",
- },
- ],
- }
- },
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
@pytest.mark.parametrize(
"path,expected_status,expected_response",
@@ -140,10 +14,151 @@ def test_openapi_schema():
("/items?q=foo&skip=5", 200, {"q": "foo", "skip": 5, "limit": 100}),
("/items?q=foo&skip=5&limit=30", 200, {"q": "foo", "skip": 5, "limit": 30}),
("/users", 200, {"q": None, "skip": 0, "limit": 100}),
- ("/openapi.json", 200, openapi_schema),
],
)
def test_get(path, expected_status, expected_response):
response = client.get(path)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ },
+ "/users/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Users",
+ "operationId": "read_users_users__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001_an.py b/tests/test_tutorial/test_dependencies/test_tutorial001_an.py
new file mode 100644
index 000000000..b1ca27ff8
--- /dev/null
+++ b/tests/test_tutorial/test_dependencies/test_tutorial001_an.py
@@ -0,0 +1,164 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from docs_src.dependencies.tutorial001_an import app
+
+client = TestClient(app)
+
+
+@pytest.mark.parametrize(
+ "path,expected_status,expected_response",
+ [
+ ("/items", 200, {"q": None, "skip": 0, "limit": 100}),
+ ("/items?q=foo", 200, {"q": "foo", "skip": 0, "limit": 100}),
+ ("/items?q=foo&skip=5", 200, {"q": "foo", "skip": 5, "limit": 100}),
+ ("/items?q=foo&skip=5&limit=30", 200, {"q": "foo", "skip": 5, "limit": 30}),
+ ("/users", 200, {"q": None, "skip": 0, "limit": 100}),
+ ],
+)
+def test_get(path, expected_status, expected_response):
+ response = client.get(path)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ },
+ "/users/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Users",
+ "operationId": "read_users_users__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001_an_py310.py b/tests/test_tutorial/test_dependencies/test_tutorial001_an_py310.py
new file mode 100644
index 000000000..70bed03f6
--- /dev/null
+++ b/tests/test_tutorial/test_dependencies/test_tutorial001_an_py310.py
@@ -0,0 +1,172 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.dependencies.tutorial001_an_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py310
+@pytest.mark.parametrize(
+ "path,expected_status,expected_response",
+ [
+ ("/items", 200, {"q": None, "skip": 0, "limit": 100}),
+ ("/items?q=foo", 200, {"q": "foo", "skip": 0, "limit": 100}),
+ ("/items?q=foo&skip=5", 200, {"q": "foo", "skip": 5, "limit": 100}),
+ ("/items?q=foo&skip=5&limit=30", 200, {"q": "foo", "skip": 5, "limit": 30}),
+ ("/users", 200, {"q": None, "skip": 0, "limit": 100}),
+ ],
+)
+def test_get(path, expected_status, expected_response, client: TestClient):
+ response = client.get(path)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ },
+ "/users/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Users",
+ "operationId": "read_users_users__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001_an_py39.py b/tests/test_tutorial/test_dependencies/test_tutorial001_an_py39.py
new file mode 100644
index 000000000..9c5723be8
--- /dev/null
+++ b/tests/test_tutorial/test_dependencies/test_tutorial001_an_py39.py
@@ -0,0 +1,172 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.dependencies.tutorial001_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py39
+@pytest.mark.parametrize(
+ "path,expected_status,expected_response",
+ [
+ ("/items", 200, {"q": None, "skip": 0, "limit": 100}),
+ ("/items?q=foo", 200, {"q": "foo", "skip": 0, "limit": 100}),
+ ("/items?q=foo&skip=5", 200, {"q": "foo", "skip": 5, "limit": 100}),
+ ("/items?q=foo&skip=5&limit=30", 200, {"q": "foo", "skip": 5, "limit": 30}),
+ ("/users", 200, {"q": None, "skip": 0, "limit": 100}),
+ ],
+)
+def test_get(path, expected_status, expected_response, client: TestClient):
+ response = client.get(path)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ },
+ "/users/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Users",
+ "operationId": "read_users_users__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py b/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py
index 32a61c821..1bcde4e9f 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py
@@ -3,126 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py310
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Q", "type": "string"},
- "name": "q",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Skip", "type": "integer", "default": 0},
- "name": "skip",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Limit", "type": "integer", "default": 100},
- "name": "limit",
- "in": "query",
- },
- ],
- }
- },
- "/users/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Users",
- "operationId": "read_users_users__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Q", "type": "string"},
- "name": "q",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Skip", "type": "integer", "default": 0},
- "name": "skip",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Limit", "type": "integer", "default": 100},
- "name": "limit",
- "in": "query",
- },
- ],
- }
- },
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -132,13 +12,6 @@ def get_client():
return client
-@needs_py310
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
@needs_py310
@pytest.mark.parametrize(
"path,expected_status,expected_response",
@@ -148,10 +21,152 @@ def test_openapi_schema(client: TestClient):
("/items?q=foo&skip=5", 200, {"q": "foo", "skip": 5, "limit": 100}),
("/items?q=foo&skip=5&limit=30", 200, {"q": "foo", "skip": 5, "limit": 30}),
("/users", 200, {"q": None, "skip": 0, "limit": 100}),
- ("/openapi.json", 200, openapi_schema),
],
)
def test_get(path, expected_status, expected_response, client: TestClient):
response = client.get(path)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ },
+ "/users/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Users",
+ "operationId": "read_users_users__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial004.py b/tests/test_tutorial/test_dependencies/test_tutorial004.py
index f2b1878d5..298bc290d 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial004.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial004.py
@@ -5,90 +5,6 @@ from docs_src.dependencies.tutorial004 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Q", "type": "string"},
- "name": "q",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Skip", "type": "integer", "default": 0},
- "name": "skip",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Limit", "type": "integer", "default": 100},
- "name": "limit",
- "in": "query",
- },
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
@pytest.mark.parametrize(
"path,expected_status,expected_response",
@@ -142,3 +58,95 @@ def test_get(path, expected_status, expected_response):
response = client.get(path)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial004_an.py b/tests/test_tutorial/test_dependencies/test_tutorial004_an.py
new file mode 100644
index 000000000..f985be8df
--- /dev/null
+++ b/tests/test_tutorial/test_dependencies/test_tutorial004_an.py
@@ -0,0 +1,152 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from docs_src.dependencies.tutorial004_an import app
+
+client = TestClient(app)
+
+
+@pytest.mark.parametrize(
+ "path,expected_status,expected_response",
+ [
+ (
+ "/items",
+ 200,
+ {
+ "items": [
+ {"item_name": "Foo"},
+ {"item_name": "Bar"},
+ {"item_name": "Baz"},
+ ]
+ },
+ ),
+ (
+ "/items?q=foo",
+ 200,
+ {
+ "items": [
+ {"item_name": "Foo"},
+ {"item_name": "Bar"},
+ {"item_name": "Baz"},
+ ],
+ "q": "foo",
+ },
+ ),
+ (
+ "/items?q=foo&skip=1",
+ 200,
+ {"items": [{"item_name": "Bar"}, {"item_name": "Baz"}], "q": "foo"},
+ ),
+ (
+ "/items?q=bar&limit=2",
+ 200,
+ {"items": [{"item_name": "Foo"}, {"item_name": "Bar"}], "q": "bar"},
+ ),
+ (
+ "/items?q=bar&skip=1&limit=1",
+ 200,
+ {"items": [{"item_name": "Bar"}], "q": "bar"},
+ ),
+ (
+ "/items?limit=1&q=bar&skip=1",
+ 200,
+ {"items": [{"item_name": "Bar"}], "q": "bar"},
+ ),
+ ],
+)
+def test_get(path, expected_status, expected_response):
+ response = client.get(path)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial004_an_py310.py b/tests/test_tutorial/test_dependencies/test_tutorial004_an_py310.py
new file mode 100644
index 000000000..fc0286702
--- /dev/null
+++ b/tests/test_tutorial/test_dependencies/test_tutorial004_an_py310.py
@@ -0,0 +1,160 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.dependencies.tutorial004_an_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py310
+@pytest.mark.parametrize(
+ "path,expected_status,expected_response",
+ [
+ (
+ "/items",
+ 200,
+ {
+ "items": [
+ {"item_name": "Foo"},
+ {"item_name": "Bar"},
+ {"item_name": "Baz"},
+ ]
+ },
+ ),
+ (
+ "/items?q=foo",
+ 200,
+ {
+ "items": [
+ {"item_name": "Foo"},
+ {"item_name": "Bar"},
+ {"item_name": "Baz"},
+ ],
+ "q": "foo",
+ },
+ ),
+ (
+ "/items?q=foo&skip=1",
+ 200,
+ {"items": [{"item_name": "Bar"}, {"item_name": "Baz"}], "q": "foo"},
+ ),
+ (
+ "/items?q=bar&limit=2",
+ 200,
+ {"items": [{"item_name": "Foo"}, {"item_name": "Bar"}], "q": "bar"},
+ ),
+ (
+ "/items?q=bar&skip=1&limit=1",
+ 200,
+ {"items": [{"item_name": "Bar"}], "q": "bar"},
+ ),
+ (
+ "/items?limit=1&q=bar&skip=1",
+ 200,
+ {"items": [{"item_name": "Bar"}], "q": "bar"},
+ ),
+ ],
+)
+def test_get(path, expected_status, expected_response, client: TestClient):
+ response = client.get(path)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial004_an_py39.py b/tests/test_tutorial/test_dependencies/test_tutorial004_an_py39.py
new file mode 100644
index 000000000..1e37673ed
--- /dev/null
+++ b/tests/test_tutorial/test_dependencies/test_tutorial004_an_py39.py
@@ -0,0 +1,160 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.dependencies.tutorial004_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py39
+@pytest.mark.parametrize(
+ "path,expected_status,expected_response",
+ [
+ (
+ "/items",
+ 200,
+ {
+ "items": [
+ {"item_name": "Foo"},
+ {"item_name": "Bar"},
+ {"item_name": "Baz"},
+ ]
+ },
+ ),
+ (
+ "/items?q=foo",
+ 200,
+ {
+ "items": [
+ {"item_name": "Foo"},
+ {"item_name": "Bar"},
+ {"item_name": "Baz"},
+ ],
+ "q": "foo",
+ },
+ ),
+ (
+ "/items?q=foo&skip=1",
+ 200,
+ {"items": [{"item_name": "Bar"}, {"item_name": "Baz"}], "q": "foo"},
+ ),
+ (
+ "/items?q=bar&limit=2",
+ 200,
+ {"items": [{"item_name": "Foo"}, {"item_name": "Bar"}], "q": "bar"},
+ ),
+ (
+ "/items?q=bar&skip=1&limit=1",
+ 200,
+ {"items": [{"item_name": "Bar"}], "q": "bar"},
+ ),
+ (
+ "/items?limit=1&q=bar&skip=1",
+ 200,
+ {"items": [{"item_name": "Bar"}], "q": "bar"},
+ ),
+ ],
+)
+def test_get(path, expected_status, expected_response, client: TestClient):
+ response = client.get(path)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py b/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py
index e3ae0c741..ab936ccdc 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py
@@ -3,84 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py310
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Q", "type": "string"},
- "name": "q",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Skip", "type": "integer", "default": 0},
- "name": "skip",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Limit", "type": "integer", "default": 100},
- "name": "limit",
- "in": "query",
- },
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -90,13 +12,6 @@ def get_client():
return client
-@needs_py310
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
@needs_py310
@pytest.mark.parametrize(
"path,expected_status,expected_response",
@@ -150,3 +65,96 @@ def test_get(path, expected_status, expected_response, client: TestClient):
response = client.get(path)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Q", "type": "string"},
+ "name": "q",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial006.py b/tests/test_tutorial/test_dependencies/test_tutorial006.py
index 2916577a2..2e9c82d71 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial006.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial006.py
@@ -4,84 +4,6 @@ from docs_src.dependencies.tutorial006 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "X-Token", "type": "string"},
- "name": "x-token",
- "in": "header",
- },
- {
- "required": True,
- "schema": {"title": "X-Key", "type": "string"},
- "name": "x-key",
- "in": "header",
- },
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get_no_headers():
response = client.get("/items/")
@@ -126,3 +48,81 @@ def test_get_valid_headers():
)
assert response.status_code == 200, response.text
assert response.json() == [{"item": "Foo"}, {"item": "Bar"}]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Key", "type": "string"},
+ "name": "x-key",
+ "in": "header",
+ },
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial006_an.py b/tests/test_tutorial/test_dependencies/test_tutorial006_an.py
new file mode 100644
index 000000000..919066dca
--- /dev/null
+++ b/tests/test_tutorial/test_dependencies/test_tutorial006_an.py
@@ -0,0 +1,128 @@
+from fastapi.testclient import TestClient
+
+from docs_src.dependencies.tutorial006_an import app
+
+client = TestClient(app)
+
+
+def test_get_no_headers():
+ response = client.get("/items/")
+ assert response.status_code == 422, response.text
+ assert response.json() == {
+ "detail": [
+ {
+ "loc": ["header", "x-token"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["header", "x-key"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ ]
+ }
+
+
+def test_get_invalid_one_header():
+ response = client.get("/items/", headers={"X-Token": "invalid"})
+ assert response.status_code == 400, response.text
+ assert response.json() == {"detail": "X-Token header invalid"}
+
+
+def test_get_invalid_second_header():
+ response = client.get(
+ "/items/", headers={"X-Token": "fake-super-secret-token", "X-Key": "invalid"}
+ )
+ assert response.status_code == 400, response.text
+ assert response.json() == {"detail": "X-Key header invalid"}
+
+
+def test_get_valid_headers():
+ response = client.get(
+ "/items/",
+ headers={
+ "X-Token": "fake-super-secret-token",
+ "X-Key": "fake-super-secret-key",
+ },
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == [{"item": "Foo"}, {"item": "Bar"}]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Key", "type": "string"},
+ "name": "x-key",
+ "in": "header",
+ },
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial006_an_py39.py b/tests/test_tutorial/test_dependencies/test_tutorial006_an_py39.py
new file mode 100644
index 000000000..c23718479
--- /dev/null
+++ b/tests/test_tutorial/test_dependencies/test_tutorial006_an_py39.py
@@ -0,0 +1,140 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.dependencies.tutorial006_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py39
+def test_get_no_headers(client: TestClient):
+ response = client.get("/items/")
+ assert response.status_code == 422, response.text
+ assert response.json() == {
+ "detail": [
+ {
+ "loc": ["header", "x-token"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["header", "x-key"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ ]
+ }
+
+
+@needs_py39
+def test_get_invalid_one_header(client: TestClient):
+ response = client.get("/items/", headers={"X-Token": "invalid"})
+ assert response.status_code == 400, response.text
+ assert response.json() == {"detail": "X-Token header invalid"}
+
+
+@needs_py39
+def test_get_invalid_second_header(client: TestClient):
+ response = client.get(
+ "/items/", headers={"X-Token": "fake-super-secret-token", "X-Key": "invalid"}
+ )
+ assert response.status_code == 400, response.text
+ assert response.json() == {"detail": "X-Key header invalid"}
+
+
+@needs_py39
+def test_get_valid_headers(client: TestClient):
+ response = client.get(
+ "/items/",
+ headers={
+ "X-Token": "fake-super-secret-token",
+ "X-Key": "fake-super-secret-key",
+ },
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == [{"item": "Foo"}, {"item": "Bar"}]
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Key", "type": "string"},
+ "name": "x-key",
+ "in": "header",
+ },
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial012.py b/tests/test_tutorial/test_dependencies/test_tutorial012.py
index e4e07395d..b92b96c01 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial012.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial012.py
@@ -4,120 +4,6 @@ from docs_src.dependencies.tutorial012 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "X-Token", "type": "string"},
- "name": "x-token",
- "in": "header",
- },
- {
- "required": True,
- "schema": {"title": "X-Key", "type": "string"},
- "name": "x-key",
- "in": "header",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- "/users/": {
- "get": {
- "summary": "Read Users",
- "operationId": "read_users_users__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "X-Token", "type": "string"},
- "name": "x-token",
- "in": "header",
- },
- {
- "required": True,
- "schema": {"title": "X-Key", "type": "string"},
- "name": "x-key",
- "in": "header",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get_no_headers_items():
response = client.get("/items/")
@@ -207,3 +93,117 @@ def test_get_valid_headers_users():
)
assert response.status_code == 200, response.text
assert response.json() == [{"username": "Rick"}, {"username": "Morty"}]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Key", "type": "string"},
+ "name": "x-key",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/users/": {
+ "get": {
+ "summary": "Read Users",
+ "operationId": "read_users_users__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Key", "type": "string"},
+ "name": "x-key",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial012_an.py b/tests/test_tutorial/test_dependencies/test_tutorial012_an.py
new file mode 100644
index 000000000..2ddb7bb53
--- /dev/null
+++ b/tests/test_tutorial/test_dependencies/test_tutorial012_an.py
@@ -0,0 +1,209 @@
+from fastapi.testclient import TestClient
+
+from docs_src.dependencies.tutorial012_an import app
+
+client = TestClient(app)
+
+
+def test_get_no_headers_items():
+ response = client.get("/items/")
+ assert response.status_code == 422, response.text
+ assert response.json() == {
+ "detail": [
+ {
+ "loc": ["header", "x-token"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["header", "x-key"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ ]
+ }
+
+
+def test_get_no_headers_users():
+ response = client.get("/users/")
+ assert response.status_code == 422, response.text
+ assert response.json() == {
+ "detail": [
+ {
+ "loc": ["header", "x-token"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["header", "x-key"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ ]
+ }
+
+
+def test_get_invalid_one_header_items():
+ response = client.get("/items/", headers={"X-Token": "invalid"})
+ assert response.status_code == 400, response.text
+ assert response.json() == {"detail": "X-Token header invalid"}
+
+
+def test_get_invalid_one_users():
+ response = client.get("/users/", headers={"X-Token": "invalid"})
+ assert response.status_code == 400, response.text
+ assert response.json() == {"detail": "X-Token header invalid"}
+
+
+def test_get_invalid_second_header_items():
+ response = client.get(
+ "/items/", headers={"X-Token": "fake-super-secret-token", "X-Key": "invalid"}
+ )
+ assert response.status_code == 400, response.text
+ assert response.json() == {"detail": "X-Key header invalid"}
+
+
+def test_get_invalid_second_header_users():
+ response = client.get(
+ "/users/", headers={"X-Token": "fake-super-secret-token", "X-Key": "invalid"}
+ )
+ assert response.status_code == 400, response.text
+ assert response.json() == {"detail": "X-Key header invalid"}
+
+
+def test_get_valid_headers_items():
+ response = client.get(
+ "/items/",
+ headers={
+ "X-Token": "fake-super-secret-token",
+ "X-Key": "fake-super-secret-key",
+ },
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == [{"item": "Portal Gun"}, {"item": "Plumbus"}]
+
+
+def test_get_valid_headers_users():
+ response = client.get(
+ "/users/",
+ headers={
+ "X-Token": "fake-super-secret-token",
+ "X-Key": "fake-super-secret-key",
+ },
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == [{"username": "Rick"}, {"username": "Morty"}]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Key", "type": "string"},
+ "name": "x-key",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/users/": {
+ "get": {
+ "summary": "Read Users",
+ "operationId": "read_users_users__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Key", "type": "string"},
+ "name": "x-key",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial012_an_py39.py b/tests/test_tutorial/test_dependencies/test_tutorial012_an_py39.py
new file mode 100644
index 000000000..595c83a53
--- /dev/null
+++ b/tests/test_tutorial/test_dependencies/test_tutorial012_an_py39.py
@@ -0,0 +1,225 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.dependencies.tutorial012_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py39
+def test_get_no_headers_items(client: TestClient):
+ response = client.get("/items/")
+ assert response.status_code == 422, response.text
+ assert response.json() == {
+ "detail": [
+ {
+ "loc": ["header", "x-token"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["header", "x-key"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ ]
+ }
+
+
+@needs_py39
+def test_get_no_headers_users(client: TestClient):
+ response = client.get("/users/")
+ assert response.status_code == 422, response.text
+ assert response.json() == {
+ "detail": [
+ {
+ "loc": ["header", "x-token"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ {
+ "loc": ["header", "x-key"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ },
+ ]
+ }
+
+
+@needs_py39
+def test_get_invalid_one_header_items(client: TestClient):
+ response = client.get("/items/", headers={"X-Token": "invalid"})
+ assert response.status_code == 400, response.text
+ assert response.json() == {"detail": "X-Token header invalid"}
+
+
+@needs_py39
+def test_get_invalid_one_users(client: TestClient):
+ response = client.get("/users/", headers={"X-Token": "invalid"})
+ assert response.status_code == 400, response.text
+ assert response.json() == {"detail": "X-Token header invalid"}
+
+
+@needs_py39
+def test_get_invalid_second_header_items(client: TestClient):
+ response = client.get(
+ "/items/", headers={"X-Token": "fake-super-secret-token", "X-Key": "invalid"}
+ )
+ assert response.status_code == 400, response.text
+ assert response.json() == {"detail": "X-Key header invalid"}
+
+
+@needs_py39
+def test_get_invalid_second_header_users(client: TestClient):
+ response = client.get(
+ "/users/", headers={"X-Token": "fake-super-secret-token", "X-Key": "invalid"}
+ )
+ assert response.status_code == 400, response.text
+ assert response.json() == {"detail": "X-Key header invalid"}
+
+
+@needs_py39
+def test_get_valid_headers_items(client: TestClient):
+ response = client.get(
+ "/items/",
+ headers={
+ "X-Token": "fake-super-secret-token",
+ "X-Key": "fake-super-secret-key",
+ },
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == [{"item": "Portal Gun"}, {"item": "Plumbus"}]
+
+
+@needs_py39
+def test_get_valid_headers_users(client: TestClient):
+ response = client.get(
+ "/users/",
+ headers={
+ "X-Token": "fake-super-secret-token",
+ "X-Key": "fake-super-secret-key",
+ },
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == [{"username": "Rick"}, {"username": "Morty"}]
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Key", "type": "string"},
+ "name": "x-key",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/users/": {
+ "get": {
+ "summary": "Read Users",
+ "operationId": "read_users_users__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "X-Token", "type": "string"},
+ "name": "x-token",
+ "in": "header",
+ },
+ {
+ "required": True,
+ "schema": {"title": "X-Key", "type": "string"},
+ "name": "x-key",
+ "in": "header",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_events/test_tutorial001.py b/tests/test_tutorial/test_events/test_tutorial001.py
index d52dd1a04..52f9beed5 100644
--- a/tests/test_tutorial/test_events/test_tutorial001.py
+++ b/tests/test_tutorial/test_events/test_tutorial001.py
@@ -2,78 +2,84 @@ from fastapi.testclient import TestClient
from docs_src.events.tutorial001 import app
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
def test_events():
with TestClient(app) as client:
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
response = client.get("/items/foo")
assert response.status_code == 200, response.text
assert response.json() == {"name": "Fighters"}
+
+
+def test_openapi_schema():
+ with TestClient(app) as client:
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ValidationError"
+ },
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_events/test_tutorial002.py b/tests/test_tutorial/test_events/test_tutorial002.py
index f6ac1e07b..882d41aa5 100644
--- a/tests/test_tutorial/test_events/test_tutorial002.py
+++ b/tests/test_tutorial/test_events/test_tutorial002.py
@@ -2,33 +2,35 @@ from fastapi.testclient import TestClient
from docs_src.events.tutorial002 import app
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- }
- }
- },
-}
-
def test_events():
with TestClient(app) as client:
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.json() == [{"name": "Foo"}]
with open("log.txt") as log:
assert "Application shutdown" in log.read()
+
+
+def test_openapi_schema():
+ with TestClient(app) as client:
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_events/test_tutorial003.py b/tests/test_tutorial/test_events/test_tutorial003.py
new file mode 100644
index 000000000..b2820b63c
--- /dev/null
+++ b/tests/test_tutorial/test_events/test_tutorial003.py
@@ -0,0 +1,92 @@
+from fastapi.testclient import TestClient
+
+from docs_src.events.tutorial003 import (
+ app,
+ fake_answer_to_everything_ml_model,
+ ml_models,
+)
+
+
+def test_events():
+ assert not ml_models, "ml_models should be empty"
+ with TestClient(app) as client:
+ assert ml_models["answer_to_everything"] == fake_answer_to_everything_ml_model
+ response = client.get("/predict", params={"x": 2})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"result": 84.0}
+ assert not ml_models, "ml_models should be empty"
+
+
+def test_openapi_schema():
+ with TestClient(app) as client:
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/predict": {
+ "get": {
+ "summary": "Predict",
+ "operationId": "predict_predict_get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "X", "type": "number"},
+ "name": "x",
+ "in": "query",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ValidationError"
+ },
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_extending_openapi/test_tutorial001.py b/tests/test_tutorial/test_extending_openapi/test_tutorial001.py
index ec56e9ca6..6e71bb2de 100644
--- a/tests/test_tutorial/test_extending_openapi/test_tutorial001.py
+++ b/tests/test_tutorial/test_extending_openapi/test_tutorial001.py
@@ -4,41 +4,43 @@ from docs_src.extending_openapi.tutorial001 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {
- "title": "Custom title",
- "version": "2.5.0",
- "description": "This is a very custom OpenAPI schema",
- "x-logo": {"url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"},
- },
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- }
- }
- },
-}
+
+def test():
+ response = client.get("/items/")
+ assert response.status_code == 200, response.text
+ assert response.json() == [{"name": "Foo"}]
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {
+ "title": "Custom title",
+ "version": "2.5.0",
+ "description": "This is a very custom OpenAPI schema",
+ "x-logo": {
+ "url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png"
+ },
+ },
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ }
+ }
+ },
+ }
+ openapi_schema = response.json()
+ # Request again to test the custom cache
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == openapi_schema
-
-
-def test():
- response = client.get("/items/")
- assert response.status_code == 200, response.text
- assert response.json() == [{"name": "Foo"}]
diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py
index 8522d7b9d..07a834990 100644
--- a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py
+++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py
@@ -5,118 +5,6 @@ from docs_src.extra_data_types.tutorial001 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "put": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__item_id__put",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "type": "string",
- "format": "uuid",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Body_read_items_items__item_id__put"
- }
- }
- }
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Body_read_items_items__item_id__put": {
- "title": "Body_read_items_items__item_id__put",
- "type": "object",
- "properties": {
- "start_datetime": {
- "title": "Start Datetime",
- "type": "string",
- "format": "date-time",
- },
- "end_datetime": {
- "title": "End Datetime",
- "type": "string",
- "format": "date-time",
- },
- "repeat_at": {
- "title": "Repeat At",
- "type": "string",
- "format": "time",
- },
- "process_after": {
- "title": "Process After",
- "type": "number",
- "format": "time-delta",
- },
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
def test_extra_types():
item_id = "ff97dd87-a4a5-4a12-b412-cde99f33e00e"
data = {
@@ -136,3 +24,114 @@ def test_extra_types():
response = client.put(f"/items/{item_id}", json=data)
assert response.status_code == 200, response.text
assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "type": "string",
+ "format": "uuid",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_read_items_items__item_id__put"
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Body_read_items_items__item_id__put": {
+ "title": "Body_read_items_items__item_id__put",
+ "type": "object",
+ "properties": {
+ "start_datetime": {
+ "title": "Start Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
+ "end_datetime": {
+ "title": "End Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
+ "repeat_at": {
+ "title": "Repeat At",
+ "type": "string",
+ "format": "time",
+ },
+ "process_after": {
+ "title": "Process After",
+ "type": "number",
+ "format": "time-delta",
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001_an.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an.py
new file mode 100644
index 000000000..76836d447
--- /dev/null
+++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an.py
@@ -0,0 +1,137 @@
+from fastapi.testclient import TestClient
+
+from docs_src.extra_data_types.tutorial001_an import app
+
+client = TestClient(app)
+
+
+def test_extra_types():
+ item_id = "ff97dd87-a4a5-4a12-b412-cde99f33e00e"
+ data = {
+ "start_datetime": "2018-12-22T14:00:00+00:00",
+ "end_datetime": "2018-12-24T15:00:00+00:00",
+ "repeat_at": "15:30:00",
+ "process_after": 300,
+ }
+ expected_response = data.copy()
+ expected_response.update(
+ {
+ "start_process": "2018-12-22T14:05:00+00:00",
+ "duration": 176_100,
+ "item_id": item_id,
+ }
+ )
+ response = client.put(f"/items/{item_id}", json=data)
+ assert response.status_code == 200, response.text
+ assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "type": "string",
+ "format": "uuid",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_read_items_items__item_id__put"
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Body_read_items_items__item_id__put": {
+ "title": "Body_read_items_items__item_id__put",
+ "type": "object",
+ "properties": {
+ "start_datetime": {
+ "title": "Start Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
+ "end_datetime": {
+ "title": "End Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
+ "repeat_at": {
+ "title": "Repeat At",
+ "type": "string",
+ "format": "time",
+ },
+ "process_after": {
+ "title": "Process After",
+ "type": "number",
+ "format": "time-delta",
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py310.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py310.py
new file mode 100644
index 000000000..158ee01b3
--- /dev/null
+++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py310.py
@@ -0,0 +1,146 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.extra_data_types.tutorial001_an_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py310
+def test_extra_types(client: TestClient):
+ item_id = "ff97dd87-a4a5-4a12-b412-cde99f33e00e"
+ data = {
+ "start_datetime": "2018-12-22T14:00:00+00:00",
+ "end_datetime": "2018-12-24T15:00:00+00:00",
+ "repeat_at": "15:30:00",
+ "process_after": 300,
+ }
+ expected_response = data.copy()
+ expected_response.update(
+ {
+ "start_process": "2018-12-22T14:05:00+00:00",
+ "duration": 176_100,
+ "item_id": item_id,
+ }
+ )
+ response = client.put(f"/items/{item_id}", json=data)
+ assert response.status_code == 200, response.text
+ assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "type": "string",
+ "format": "uuid",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_read_items_items__item_id__put"
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Body_read_items_items__item_id__put": {
+ "title": "Body_read_items_items__item_id__put",
+ "type": "object",
+ "properties": {
+ "start_datetime": {
+ "title": "Start Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
+ "end_datetime": {
+ "title": "End Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
+ "repeat_at": {
+ "title": "Repeat At",
+ "type": "string",
+ "format": "time",
+ },
+ "process_after": {
+ "title": "Process After",
+ "type": "number",
+ "format": "time-delta",
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py39.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py39.py
new file mode 100644
index 000000000..5be6452ee
--- /dev/null
+++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py39.py
@@ -0,0 +1,146 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.extra_data_types.tutorial001_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py39
+def test_extra_types(client: TestClient):
+ item_id = "ff97dd87-a4a5-4a12-b412-cde99f33e00e"
+ data = {
+ "start_datetime": "2018-12-22T14:00:00+00:00",
+ "end_datetime": "2018-12-24T15:00:00+00:00",
+ "repeat_at": "15:30:00",
+ "process_after": 300,
+ }
+ expected_response = data.copy()
+ expected_response.update(
+ {
+ "start_process": "2018-12-22T14:05:00+00:00",
+ "duration": 176_100,
+ "item_id": item_id,
+ }
+ )
+ response = client.put(f"/items/{item_id}", json=data)
+ assert response.status_code == 200, response.text
+ assert response.json() == expected_response
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "type": "string",
+ "format": "uuid",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_read_items_items__item_id__put"
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Body_read_items_items__item_id__put": {
+ "title": "Body_read_items_items__item_id__put",
+ "type": "object",
+ "properties": {
+ "start_datetime": {
+ "title": "Start Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
+ "end_datetime": {
+ "title": "End Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
+ "repeat_at": {
+ "title": "Repeat At",
+ "type": "string",
+ "format": "time",
+ },
+ "process_after": {
+ "title": "Process After",
+ "type": "number",
+ "format": "time-delta",
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py
index 4efdecc53..5413fe428 100644
--- a/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py
@@ -3,111 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py310
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "put": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__item_id__put",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Item Id",
- "type": "string",
- "format": "uuid",
- },
- "name": "item_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Body_read_items_items__item_id__put"
- }
- }
- }
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Body_read_items_items__item_id__put": {
- "title": "Body_read_items_items__item_id__put",
- "type": "object",
- "properties": {
- "start_datetime": {
- "title": "Start Datetime",
- "type": "string",
- "format": "date-time",
- },
- "end_datetime": {
- "title": "End Datetime",
- "type": "string",
- "format": "date-time",
- },
- "repeat_at": {
- "title": "Repeat At",
- "type": "string",
- "format": "time",
- },
- "process_after": {
- "title": "Process After",
- "type": "number",
- "format": "time-delta",
- },
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -117,13 +12,6 @@ def get_client():
return client
-@needs_py310
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
@needs_py310
def test_extra_types(client: TestClient):
item_id = "ff97dd87-a4a5-4a12-b412-cde99f33e00e"
@@ -144,3 +32,115 @@ def test_extra_types(client: TestClient):
response = client.put(f"/items/{item_id}", json=data)
assert response.status_code == 200, response.text
assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "put": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__item_id__put",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {
+ "title": "Item Id",
+ "type": "string",
+ "format": "uuid",
+ },
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_read_items_items__item_id__put"
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Body_read_items_items__item_id__put": {
+ "title": "Body_read_items_items__item_id__put",
+ "type": "object",
+ "properties": {
+ "start_datetime": {
+ "title": "Start Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
+ "end_datetime": {
+ "title": "End Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
+ "repeat_at": {
+ "title": "Repeat At",
+ "type": "string",
+ "format": "time",
+ },
+ "process_after": {
+ "title": "Process After",
+ "type": "number",
+ "format": "time-delta",
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial003.py b/tests/test_tutorial/test_extra_models/test_tutorial003.py
index f1433470c..f08bf4c50 100644
--- a/tests/test_tutorial/test_extra_models/test_tutorial003.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial003.py
@@ -4,107 +4,6 @@ from docs_src.extra_models.tutorial003 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Read Item Items Item Id Get",
- "anyOf": [
- {"$ref": "#/components/schemas/PlaneItem"},
- {"$ref": "#/components/schemas/CarItem"},
- ],
- }
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Item",
- "operationId": "read_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "PlaneItem": {
- "title": "PlaneItem",
- "required": ["description", "size"],
- "type": "object",
- "properties": {
- "description": {"title": "Description", "type": "string"},
- "type": {"title": "Type", "type": "string", "default": "plane"},
- "size": {"title": "Size", "type": "integer"},
- },
- },
- "CarItem": {
- "title": "CarItem",
- "required": ["description"],
- "type": "object",
- "properties": {
- "description": {"title": "Description", "type": "string"},
- "type": {"title": "Type", "type": "string", "default": "car"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get_car():
response = client.get("/items/item1")
@@ -123,3 +22,104 @@ def test_get_plane():
"type": "plane",
"size": 5,
}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Read Item Items Item Id Get",
+ "anyOf": [
+ {"$ref": "#/components/schemas/PlaneItem"},
+ {"$ref": "#/components/schemas/CarItem"},
+ ],
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "PlaneItem": {
+ "title": "PlaneItem",
+ "required": ["description", "size"],
+ "type": "object",
+ "properties": {
+ "description": {"title": "Description", "type": "string"},
+ "type": {"title": "Type", "type": "string", "default": "plane"},
+ "size": {"title": "Size", "type": "integer"},
+ },
+ },
+ "CarItem": {
+ "title": "CarItem",
+ "required": ["description"],
+ "type": "object",
+ "properties": {
+ "description": {"title": "Description", "type": "string"},
+ "type": {"title": "Type", "type": "string", "default": "car"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py b/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py
index 56fd83ad3..407c71787 100644
--- a/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py
@@ -3,101 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py310
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Read Item Items Item Id Get",
- "anyOf": [
- {"$ref": "#/components/schemas/PlaneItem"},
- {"$ref": "#/components/schemas/CarItem"},
- ],
- }
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Item",
- "operationId": "read_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "PlaneItem": {
- "title": "PlaneItem",
- "required": ["description", "size"],
- "type": "object",
- "properties": {
- "description": {"title": "Description", "type": "string"},
- "type": {"title": "Type", "type": "string", "default": "plane"},
- "size": {"title": "Size", "type": "integer"},
- },
- },
- "CarItem": {
- "title": "CarItem",
- "required": ["description"],
- "type": "object",
- "properties": {
- "description": {"title": "Description", "type": "string"},
- "type": {"title": "Type", "type": "string", "default": "car"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -107,13 +12,6 @@ def get_client():
return client
-@needs_py310
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
@needs_py310
def test_get_car(client: TestClient):
response = client.get("/items/item1")
@@ -133,3 +31,105 @@ def test_get_plane(client: TestClient):
"type": "plane",
"size": 5,
}
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Read Item Items Item Id Get",
+ "anyOf": [
+ {"$ref": "#/components/schemas/PlaneItem"},
+ {"$ref": "#/components/schemas/CarItem"},
+ ],
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "PlaneItem": {
+ "title": "PlaneItem",
+ "required": ["description", "size"],
+ "type": "object",
+ "properties": {
+ "description": {"title": "Description", "type": "string"},
+ "type": {"title": "Type", "type": "string", "default": "plane"},
+ "size": {"title": "Size", "type": "integer"},
+ },
+ },
+ "CarItem": {
+ "title": "CarItem",
+ "required": ["description"],
+ "type": "object",
+ "properties": {
+ "description": {"title": "Description", "type": "string"},
+ "type": {"title": "Type", "type": "string", "default": "car"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial004.py b/tests/test_tutorial/test_extra_models/test_tutorial004.py
index 548fb8834..47790ba8f 100644
--- a/tests/test_tutorial/test_extra_models/test_tutorial004.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial004.py
@@ -4,52 +4,6 @@ from docs_src.extra_models.tutorial004 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Read Items Items Get",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Item"},
- }
- }
- },
- }
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "description"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "description": {"title": "Description", "type": "string"},
- },
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get_items():
response = client.get("/items/")
@@ -58,3 +12,47 @@ def test_get_items():
{"name": "Foo", "description": "There comes my hero"},
{"name": "Red", "description": "It's my aeroplane"},
]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Read Items Items Get",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ }
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "description"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ },
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial004_py39.py b/tests/test_tutorial/test_extra_models/test_tutorial004_py39.py
index 7f4f5b9be..a98700172 100644
--- a/tests/test_tutorial/test_extra_models/test_tutorial004_py39.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial004_py39.py
@@ -3,46 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py39
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Read Items Items Get",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Item"},
- }
- }
- },
- }
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "description"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "description": {"title": "Description", "type": "string"},
- },
- }
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -52,13 +12,6 @@ def get_client():
return client
-@needs_py39
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
@needs_py39
def test_get_items(client: TestClient):
response = client.get("/items/")
@@ -67,3 +20,48 @@ def test_get_items(client: TestClient):
{"name": "Foo", "description": "There comes my hero"},
{"name": "Red", "description": "It's my aeroplane"},
]
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Read Items Items Get",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
+ }
+ },
+ }
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "description"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "description": {"title": "Description", "type": "string"},
+ },
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial005.py b/tests/test_tutorial/test_extra_models/test_tutorial005.py
index c3dfaa42f..7c094b253 100644
--- a/tests/test_tutorial/test_extra_models/test_tutorial005.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial005.py
@@ -4,41 +4,39 @@ from docs_src.extra_models.tutorial005 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/keyword-weights/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Read Keyword Weights Keyword Weights Get",
- "type": "object",
- "additionalProperties": {"type": "number"},
- }
- }
- },
- }
- },
- "summary": "Read Keyword Weights",
- "operationId": "read_keyword_weights_keyword_weights__get",
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get_items():
response = client.get("/keyword-weights/")
assert response.status_code == 200, response.text
assert response.json() == {"foo": 2.3, "bar": 3.4}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/keyword-weights/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Read Keyword Weights Keyword Weights Get",
+ "type": "object",
+ "additionalProperties": {"type": "number"},
+ }
+ }
+ },
+ }
+ },
+ "summary": "Read Keyword Weights",
+ "operationId": "read_keyword_weights_keyword_weights__get",
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_extra_models/test_tutorial005_py39.py b/tests/test_tutorial/test_extra_models/test_tutorial005_py39.py
index 3bb5a99f1..b40386450 100644
--- a/tests/test_tutorial/test_extra_models/test_tutorial005_py39.py
+++ b/tests/test_tutorial/test_extra_models/test_tutorial005_py39.py
@@ -3,33 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py39
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/keyword-weights/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Read Keyword Weights Keyword Weights Get",
- "type": "object",
- "additionalProperties": {"type": "number"},
- }
- }
- },
- }
- },
- "summary": "Read Keyword Weights",
- "operationId": "read_keyword_weights_keyword_weights__get",
- }
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -40,14 +13,39 @@ def get_client():
@needs_py39
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
+def test_get_items(client: TestClient):
+ response = client.get("/keyword-weights/")
assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
+ assert response.json() == {"foo": 2.3, "bar": 3.4}
@needs_py39
-def test_get_items(client: TestClient):
- response = client.get("/keyword-weights/")
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
assert response.status_code == 200, response.text
- assert response.json() == {"foo": 2.3, "bar": 3.4}
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/keyword-weights/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Read Keyword Weights Keyword Weights Get",
+ "type": "object",
+ "additionalProperties": {"type": "number"},
+ }
+ }
+ },
+ }
+ },
+ "summary": "Read Keyword Weights",
+ "operationId": "read_keyword_weights_keyword_weights__get",
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_first_steps/test_tutorial001.py b/tests/test_tutorial/test_first_steps/test_tutorial001.py
index 48d42285c..ea37aec53 100644
--- a/tests/test_tutorial/test_first_steps/test_tutorial001.py
+++ b/tests/test_tutorial/test_first_steps/test_tutorial001.py
@@ -5,35 +5,38 @@ from docs_src.first_steps.tutorial001 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Root",
- "operationId": "root__get",
- }
- }
- },
-}
-
@pytest.mark.parametrize(
"path,expected_status,expected_response",
[
("/", 200, {"message": "Hello World"}),
("/nonexistent", 404, {"detail": "Not Found"}),
- ("/openapi.json", 200, openapi_schema),
],
)
def test_get_path(path, expected_status, expected_response):
response = client.get(path)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Root",
+ "operationId": "root__get",
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_generate_clients/test_tutorial003.py b/tests/test_tutorial/test_generate_clients/test_tutorial003.py
index 128fcea30..8b22eab9e 100644
--- a/tests/test_tutorial/test_generate_clients/test_tutorial003.py
+++ b/tests/test_tutorial/test_generate_clients/test_tutorial003.py
@@ -4,185 +4,184 @@ from docs_src.generate_clients.tutorial003 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "tags": ["items"],
- "summary": "Get Items",
- "operationId": "items-get_items",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Items-Get Items",
- "type": "array",
- "items": {"$ref": "#/components/schemas/Item"},
+
+def test_post_items():
+ response = client.post("/items/", json={"name": "Foo", "price": 5})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"message": "Item received"}
+
+
+def test_post_users():
+ response = client.post(
+ "/users/", json={"username": "Foo", "email": "foo@example.com"}
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == {"message": "User received"}
+
+
+def test_get_items():
+ response = client.get("/items/")
+ assert response.status_code == 200, response.text
+ assert response.json() == [
+ {"name": "Plumbus", "price": 3},
+ {"name": "Portal Gun", "price": 9001},
+ ]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "tags": ["items"],
+ "summary": "Get Items",
+ "operationId": "items-get_items",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Items-Get Items",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/Item"},
+ }
}
- }
- },
- }
- },
- },
- "post": {
- "tags": ["items"],
- "summary": "Create Item",
- "operationId": "items-create_item",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
+ },
}
},
- "required": True,
},
- "responses": {
- "200": {
- "description": "Successful Response",
+ "post": {
+ "tags": ["items"],
+ "summary": "Create Item",
+ "operationId": "items-create_item",
+ "requestBody": {
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/ResponseMessage"
- }
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
+ "required": True,
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ResponseMessage"
+ }
}
- }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
},
},
- },
- "/users/": {
- "post": {
- "tags": ["users"],
- "summary": "Create User",
- "operationId": "users-create_user",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/User"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
+ "/users/": {
+ "post": {
+ "tags": ["users"],
+ "summary": "Create User",
+ "operationId": "users-create_user",
+ "requestBody": {
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/ResponseMessage"
- }
+ "schema": {"$ref": "#/components/schemas/User"}
}
},
+ "required": True,
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ResponseMessage"
+ }
}
- }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
- }
+ }
+ },
},
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
},
- },
- "Item": {
- "title": "Item",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "price": {"title": "Price", "type": "number"},
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ },
},
- },
- "ResponseMessage": {
- "title": "ResponseMessage",
- "required": ["message"],
- "type": "object",
- "properties": {"message": {"title": "Message", "type": "string"}},
- },
- "User": {
- "title": "User",
- "required": ["username", "email"],
- "type": "object",
- "properties": {
- "username": {"title": "Username", "type": "string"},
- "email": {"title": "Email", "type": "string"},
+ "ResponseMessage": {
+ "title": "ResponseMessage",
+ "required": ["message"],
+ "type": "object",
+ "properties": {"message": {"title": "Message", "type": "string"}},
},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ "User": {
+ "title": "User",
+ "required": ["username", "email"],
+ "type": "object",
+ "properties": {
+ "username": {"title": "Username", "type": "string"},
+ "email": {"title": "Email", "type": "string"},
},
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
},
- },
- }
- },
-}
-
-
-def test_openapi():
- with client:
- response = client.get("/openapi.json")
-
- assert response.json() == openapi_schema
-
-
-def test_post_items():
- response = client.post("/items/", json={"name": "Foo", "price": 5})
- assert response.status_code == 200, response.text
- assert response.json() == {"message": "Item received"}
-
-
-def test_post_users():
- response = client.post(
- "/users/", json={"username": "Foo", "email": "foo@example.com"}
- )
- assert response.status_code == 200, response.text
- assert response.json() == {"message": "User received"}
-
-
-def test_get_items():
- response = client.get("/items/")
- assert response.status_code == 200, response.text
- assert response.json() == [
- {"name": "Plumbus", "price": 3},
- {"name": "Portal Gun", "price": 9001},
- ]
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial001.py b/tests/test_tutorial/test_handling_errors/test_tutorial001.py
index ffd79ccff..99a1053ca 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial001.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial001.py
@@ -4,78 +4,6 @@ from docs_src.handling_errors.tutorial001 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Item",
- "operationId": "read_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get_item():
response = client.get("/items/foo")
@@ -88,3 +16,75 @@ def test_get_item_not_found():
assert response.status_code == 404, response.text
assert response.headers.get("x-error") is None
assert response.json() == {"detail": "Item not found"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial002.py b/tests/test_tutorial/test_handling_errors/test_tutorial002.py
index e678499c6..091c74f4d 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial002.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial002.py
@@ -4,78 +4,6 @@ from docs_src.handling_errors.tutorial002 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items-header/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Item Header",
- "operationId": "read_item_header_items_header__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get_item_header():
response = client.get("/items-header/foo")
@@ -88,3 +16,75 @@ def test_get_item_not_found_header():
assert response.status_code == 404, response.text
assert response.headers.get("x-error") == "There goes my error"
assert response.json() == {"detail": "Item not found"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items-header/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item Header",
+ "operationId": "read_item_header_items_header__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial003.py b/tests/test_tutorial/test_handling_errors/test_tutorial003.py
index a01726dc2..1639cb1d8 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial003.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial003.py
@@ -4,78 +4,6 @@ from docs_src.handling_errors.tutorial003 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/unicorns/{name}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Unicorn",
- "operationId": "read_unicorn_unicorns__name__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Name", "type": "string"},
- "name": "name",
- "in": "path",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get():
response = client.get("/unicorns/shinny")
@@ -89,3 +17,75 @@ def test_get_exception():
assert response.json() == {
"message": "Oops! yolo did something. There goes a rainbow..."
}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/unicorns/{name}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Unicorn",
+ "operationId": "read_unicorn_unicorns__name__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Name", "type": "string"},
+ "name": "name",
+ "in": "path",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial004.py b/tests/test_tutorial/test_handling_errors/test_tutorial004.py
index 0b5f74798..246f3b94c 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial004.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial004.py
@@ -4,78 +4,6 @@ from docs_src.handling_errors.tutorial004 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Item",
- "operationId": "read_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "integer"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get_validation_error():
response = client.get("/items/foo")
@@ -98,3 +26,75 @@ def test_get():
response = client.get("/items/2")
assert response.status_code == 200, response.text
assert response.json() == {"item_id": 2}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "integer"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial005.py b/tests/test_tutorial/test_handling_errors/test_tutorial005.py
index 253f3d006..af47fd1a4 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial005.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial005.py
@@ -4,87 +4,6 @@ from docs_src.handling_errors.tutorial005 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "post": {
- "summary": "Create Item",
- "operationId": "create_item_items__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "Item": {
- "title": "Item",
- "required": ["title", "size"],
- "type": "object",
- "properties": {
- "title": {"title": "Title", "type": "string"},
- "size": {"title": "Size", "type": "integer"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_post_validation_error():
response = client.post("/items/", json={"title": "towel", "size": "XL"})
@@ -106,3 +25,84 @@ def test_post():
response = client.post("/items/", json=data)
assert response.status_code == 200, response.text
assert response.json() == data
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "post": {
+ "summary": "Create Item",
+ "operationId": "create_item_items__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "Item": {
+ "title": "Item",
+ "required": ["title", "size"],
+ "type": "object",
+ "properties": {
+ "title": {"title": "Title", "type": "string"},
+ "size": {"title": "Size", "type": "integer"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial006.py b/tests/test_tutorial/test_handling_errors/test_tutorial006.py
index 21233d7bb..4a39bd102 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial006.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial006.py
@@ -4,78 +4,6 @@ from docs_src.handling_errors.tutorial006 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Item",
- "operationId": "read_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "integer"},
- "name": "item_id",
- "in": "path",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get_validation_error():
response = client.get("/items/foo")
@@ -101,3 +29,75 @@ def test_get():
response = client.get("/items/2")
assert response.status_code == 200, response.text
assert response.json() == {"item_id": 2}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Item",
+ "operationId": "read_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "integer"},
+ "name": "item_id",
+ "in": "path",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_header_params/test_tutorial001.py b/tests/test_tutorial/test_header_params/test_tutorial001.py
index 273cf3249..80f502d6a 100644
--- a/tests/test_tutorial/test_header_params/test_tutorial001.py
+++ b/tests/test_tutorial/test_header_params/test_tutorial001.py
@@ -6,77 +6,9 @@ from docs_src.header_params.tutorial001 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "User-Agent", "type": "string"},
- "name": "user-agent",
- "in": "header",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
@pytest.mark.parametrize(
"path,headers,expected_status,expected_response",
[
- ("/openapi.json", None, 200, openapi_schema),
("/items", None, 200, {"User-Agent": "testclient"}),
("/items", {"X-Header": "notvalid"}, 200, {"User-Agent": "testclient"}),
("/items", {"User-Agent": "FastAPI test"}, 200, {"User-Agent": "FastAPI test"}),
@@ -86,3 +18,75 @@ def test(path, headers, expected_status, expected_response):
response = client.get(path, headers=headers)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+def test_openapi():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "User-Agent", "type": "string"},
+ "name": "user-agent",
+ "in": "header",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_header_params/test_tutorial001_an.py b/tests/test_tutorial/test_header_params/test_tutorial001_an.py
new file mode 100644
index 000000000..f0ad7b816
--- /dev/null
+++ b/tests/test_tutorial/test_header_params/test_tutorial001_an.py
@@ -0,0 +1,92 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from docs_src.header_params.tutorial001_an import app
+
+client = TestClient(app)
+
+
+@pytest.mark.parametrize(
+ "path,headers,expected_status,expected_response",
+ [
+ ("/items", None, 200, {"User-Agent": "testclient"}),
+ ("/items", {"X-Header": "notvalid"}, 200, {"User-Agent": "testclient"}),
+ ("/items", {"User-Agent": "FastAPI test"}, 200, {"User-Agent": "FastAPI test"}),
+ ],
+)
+def test(path, headers, expected_status, expected_response):
+ response = client.get(path, headers=headers)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "User-Agent", "type": "string"},
+ "name": "user-agent",
+ "in": "header",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_header_params/test_tutorial001_an_py310.py b/tests/test_tutorial/test_header_params/test_tutorial001_an_py310.py
new file mode 100644
index 000000000..d095c7123
--- /dev/null
+++ b/tests/test_tutorial/test_header_params/test_tutorial001_an_py310.py
@@ -0,0 +1,100 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.header_params.tutorial001_an_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py310
+@pytest.mark.parametrize(
+ "path,headers,expected_status,expected_response",
+ [
+ ("/items", None, 200, {"User-Agent": "testclient"}),
+ ("/items", {"X-Header": "notvalid"}, 200, {"User-Agent": "testclient"}),
+ ("/items", {"User-Agent": "FastAPI test"}, 200, {"User-Agent": "FastAPI test"}),
+ ],
+)
+def test(path, headers, expected_status, expected_response, client: TestClient):
+ response = client.get(path, headers=headers)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "User-Agent", "type": "string"},
+ "name": "user-agent",
+ "in": "header",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_header_params/test_tutorial001_py310.py b/tests/test_tutorial/test_header_params/test_tutorial001_py310.py
index 77a60eb9d..bf176bba2 100644
--- a/tests/test_tutorial/test_header_params/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_header_params/test_tutorial001_py310.py
@@ -3,72 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py310
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "User-Agent", "type": "string"},
- "name": "user-agent",
- "in": "header",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -82,7 +16,6 @@ def get_client():
@pytest.mark.parametrize(
"path,headers,expected_status,expected_response",
[
- ("/openapi.json", None, 200, openapi_schema),
("/items", None, 200, {"User-Agent": "testclient"}),
("/items", {"X-Header": "notvalid"}, 200, {"User-Agent": "testclient"}),
("/items", {"User-Agent": "FastAPI test"}, 200, {"User-Agent": "FastAPI test"}),
@@ -92,3 +25,76 @@ def test(path, headers, expected_status, expected_response, client: TestClient):
response = client.get(path, headers=headers)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "User-Agent", "type": "string"},
+ "name": "user-agent",
+ "in": "header",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_header_params/test_tutorial002.py b/tests/test_tutorial/test_header_params/test_tutorial002.py
new file mode 100644
index 000000000..516abda8b
--- /dev/null
+++ b/tests/test_tutorial/test_header_params/test_tutorial002.py
@@ -0,0 +1,103 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from docs_src.header_params.tutorial002 import app
+
+client = TestClient(app)
+
+
+@pytest.mark.parametrize(
+ "path,headers,expected_status,expected_response",
+ [
+ ("/items", None, 200, {"strange_header": None}),
+ ("/items", {"X-Header": "notvalid"}, 200, {"strange_header": None}),
+ (
+ "/items",
+ {"strange_header": "FastAPI test"},
+ 200,
+ {"strange_header": "FastAPI test"},
+ ),
+ (
+ "/items",
+ {"strange-header": "Not really underscore"},
+ 200,
+ {"strange_header": None},
+ ),
+ ],
+)
+def test(path, headers, expected_status, expected_response):
+ response = client.get(path, headers=headers)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Strange Header", "type": "string"},
+ "name": "strange_header",
+ "in": "header",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_header_params/test_tutorial002_an.py b/tests/test_tutorial/test_header_params/test_tutorial002_an.py
new file mode 100644
index 000000000..97493e604
--- /dev/null
+++ b/tests/test_tutorial/test_header_params/test_tutorial002_an.py
@@ -0,0 +1,103 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from docs_src.header_params.tutorial002_an import app
+
+client = TestClient(app)
+
+
+@pytest.mark.parametrize(
+ "path,headers,expected_status,expected_response",
+ [
+ ("/items", None, 200, {"strange_header": None}),
+ ("/items", {"X-Header": "notvalid"}, 200, {"strange_header": None}),
+ (
+ "/items",
+ {"strange_header": "FastAPI test"},
+ 200,
+ {"strange_header": "FastAPI test"},
+ ),
+ (
+ "/items",
+ {"strange-header": "Not really underscore"},
+ 200,
+ {"strange_header": None},
+ ),
+ ],
+)
+def test(path, headers, expected_status, expected_response):
+ response = client.get(path, headers=headers)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Strange Header", "type": "string"},
+ "name": "strange_header",
+ "in": "header",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_header_params/test_tutorial002_an_py310.py b/tests/test_tutorial/test_header_params/test_tutorial002_an_py310.py
new file mode 100644
index 000000000..e0c60342a
--- /dev/null
+++ b/tests/test_tutorial/test_header_params/test_tutorial002_an_py310.py
@@ -0,0 +1,111 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.header_params.tutorial002_an_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py310
+@pytest.mark.parametrize(
+ "path,headers,expected_status,expected_response",
+ [
+ ("/items", None, 200, {"strange_header": None}),
+ ("/items", {"X-Header": "notvalid"}, 200, {"strange_header": None}),
+ (
+ "/items",
+ {"strange_header": "FastAPI test"},
+ 200,
+ {"strange_header": "FastAPI test"},
+ ),
+ (
+ "/items",
+ {"strange-header": "Not really underscore"},
+ 200,
+ {"strange_header": None},
+ ),
+ ],
+)
+def test(path, headers, expected_status, expected_response, client: TestClient):
+ response = client.get(path, headers=headers)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Strange Header", "type": "string"},
+ "name": "strange_header",
+ "in": "header",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_header_params/test_tutorial002_an_py39.py b/tests/test_tutorial/test_header_params/test_tutorial002_an_py39.py
new file mode 100644
index 000000000..c1bc5faf8
--- /dev/null
+++ b/tests/test_tutorial/test_header_params/test_tutorial002_an_py39.py
@@ -0,0 +1,114 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.header_params.tutorial002_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py39
+@pytest.mark.parametrize(
+ "path,headers,expected_status,expected_response",
+ [
+ ("/items", None, 200, {"strange_header": None}),
+ ("/items", {"X-Header": "notvalid"}, 200, {"strange_header": None}),
+ (
+ "/items",
+ {"strange_header": "FastAPI test"},
+ 200,
+ {"strange_header": "FastAPI test"},
+ ),
+ (
+ "/items",
+ {"strange-header": "Not really underscore"},
+ 200,
+ {"strange_header": None},
+ ),
+ ],
+)
+def test(path, headers, expected_status, expected_response, client: TestClient):
+ response = client.get(path, headers=headers)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py39
+def test_openapi_schema():
+ from docs_src.header_params.tutorial002_an_py39 import app
+
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Strange Header", "type": "string"},
+ "name": "strange_header",
+ "in": "header",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_header_params/test_tutorial002_py310.py b/tests/test_tutorial/test_header_params/test_tutorial002_py310.py
new file mode 100644
index 000000000..81871b8c6
--- /dev/null
+++ b/tests/test_tutorial/test_header_params/test_tutorial002_py310.py
@@ -0,0 +1,114 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.header_params.tutorial002_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py310
+@pytest.mark.parametrize(
+ "path,headers,expected_status,expected_response",
+ [
+ ("/items", None, 200, {"strange_header": None}),
+ ("/items", {"X-Header": "notvalid"}, 200, {"strange_header": None}),
+ (
+ "/items",
+ {"strange_header": "FastAPI test"},
+ 200,
+ {"strange_header": "FastAPI test"},
+ ),
+ (
+ "/items",
+ {"strange-header": "Not really underscore"},
+ 200,
+ {"strange_header": None},
+ ),
+ ],
+)
+def test(path, headers, expected_status, expected_response, client: TestClient):
+ response = client.get(path, headers=headers)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema():
+ from docs_src.header_params.tutorial002_py310 import app
+
+ client = TestClient(app)
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {"title": "Strange Header", "type": "string"},
+ "name": "strange_header",
+ "in": "header",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_header_params/test_tutorial003.py b/tests/test_tutorial/test_header_params/test_tutorial003.py
new file mode 100644
index 000000000..99dd9e25f
--- /dev/null
+++ b/tests/test_tutorial/test_header_params/test_tutorial003.py
@@ -0,0 +1,98 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from docs_src.header_params.tutorial003 import app
+
+client = TestClient(app)
+
+
+@pytest.mark.parametrize(
+ "path,headers,expected_status,expected_response",
+ [
+ ("/items", None, 200, {"X-Token values": None}),
+ ("/items", {"x-token": "foo"}, 200, {"X-Token values": ["foo"]}),
+ # TODO: fix this, is it a bug?
+ # ("/items", [("x-token", "foo"), ("x-token", "bar")], 200, {"X-Token values": ["foo", "bar"]}),
+ ],
+)
+def test(path, headers, expected_status, expected_response):
+ response = client.get(path, headers=headers)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ # insert_assert(response.json())
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "X-Token",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "name": "x-token",
+ "in": "header",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_header_params/test_tutorial003_an.py b/tests/test_tutorial/test_header_params/test_tutorial003_an.py
new file mode 100644
index 000000000..4477da7a8
--- /dev/null
+++ b/tests/test_tutorial/test_header_params/test_tutorial003_an.py
@@ -0,0 +1,98 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from docs_src.header_params.tutorial003_an import app
+
+client = TestClient(app)
+
+
+@pytest.mark.parametrize(
+ "path,headers,expected_status,expected_response",
+ [
+ ("/items", None, 200, {"X-Token values": None}),
+ ("/items", {"x-token": "foo"}, 200, {"X-Token values": ["foo"]}),
+ # TODO: fix this, is it a bug?
+ # ("/items", [("x-token", "foo"), ("x-token", "bar")], 200, {"X-Token values": ["foo", "bar"]}),
+ ],
+)
+def test(path, headers, expected_status, expected_response):
+ response = client.get(path, headers=headers)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ # insert_assert(response.json())
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "X-Token",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "name": "x-token",
+ "in": "header",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_header_params/test_tutorial003_an_py310.py b/tests/test_tutorial/test_header_params/test_tutorial003_an_py310.py
new file mode 100644
index 000000000..b52304a2b
--- /dev/null
+++ b/tests/test_tutorial/test_header_params/test_tutorial003_an_py310.py
@@ -0,0 +1,106 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.header_params.tutorial003_an_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py310
+@pytest.mark.parametrize(
+ "path,headers,expected_status,expected_response",
+ [
+ ("/items", None, 200, {"X-Token values": None}),
+ ("/items", {"x-token": "foo"}, 200, {"X-Token values": ["foo"]}),
+ # TODO: fix this, is it a bug?
+ # ("/items", [("x-token", "foo"), ("x-token", "bar")], 200, {"X-Token values": ["foo", "bar"]}),
+ ],
+)
+def test(path, headers, expected_status, expected_response, client: TestClient):
+ response = client.get(path, headers=headers)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ # insert_assert(response.json())
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "X-Token",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "name": "x-token",
+ "in": "header",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_header_params/test_tutorial003_an_py39.py b/tests/test_tutorial/test_header_params/test_tutorial003_an_py39.py
new file mode 100644
index 000000000..dffdd1622
--- /dev/null
+++ b/tests/test_tutorial/test_header_params/test_tutorial003_an_py39.py
@@ -0,0 +1,106 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.header_params.tutorial003_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py310
+@pytest.mark.parametrize(
+ "path,headers,expected_status,expected_response",
+ [
+ ("/items", None, 200, {"X-Token values": None}),
+ ("/items", {"x-token": "foo"}, 200, {"X-Token values": ["foo"]}),
+ # TODO: fix this, is it a bug?
+ # ("/items", [("x-token", "foo"), ("x-token", "bar")], 200, {"X-Token values": ["foo", "bar"]}),
+ ],
+)
+def test(path, headers, expected_status, expected_response, client: TestClient):
+ response = client.get(path, headers=headers)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ # insert_assert(response.json())
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "X-Token",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "name": "x-token",
+ "in": "header",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_header_params/test_tutorial003_py310.py b/tests/test_tutorial/test_header_params/test_tutorial003_py310.py
new file mode 100644
index 000000000..64ef7b22a
--- /dev/null
+++ b/tests/test_tutorial/test_header_params/test_tutorial003_py310.py
@@ -0,0 +1,106 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.header_params.tutorial003_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py310
+@pytest.mark.parametrize(
+ "path,headers,expected_status,expected_response",
+ [
+ ("/items", None, 200, {"X-Token values": None}),
+ ("/items", {"x-token": "foo"}, 200, {"X-Token values": ["foo"]}),
+ # TODO: fix this, is it a bug?
+ # ("/items", [("x-token", "foo"), ("x-token", "bar")], 200, {"X-Token values": ["foo", "bar"]}),
+ ],
+)
+def test(path, headers, expected_status, expected_response, client: TestClient):
+ response = client.get(path, headers=headers)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ # insert_assert(response.json())
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "X-Token",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "name": "x-token",
+ "in": "header",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_metadata/test_tutorial001.py b/tests/test_tutorial/test_metadata/test_tutorial001.py
index b7281e293..f1ddc3259 100644
--- a/tests/test_tutorial/test_metadata/test_tutorial001.py
+++ b/tests/test_tutorial/test_metadata/test_tutorial001.py
@@ -4,47 +4,45 @@ from docs_src.metadata.tutorial001 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {
- "title": "ChimichangApp",
- "description": "\nChimichangApp API helps you do awesome stuff. 🚀\n\n## Items\n\nYou can **read items**.\n\n## Users\n\nYou will be able to:\n\n* **Create users** (_not implemented_).\n* **Read users** (_not implemented_).\n",
- "termsOfService": "http://example.com/terms/",
- "contact": {
- "name": "Deadpoolio the Amazing",
- "url": "http://x-force.example.com/contact/",
- "email": "dp@x-force.example.com",
- },
- "license": {
- "name": "Apache 2.0",
- "url": "https://www.apache.org/licenses/LICENSE-2.0.html",
- },
- "version": "0.0.1",
- },
- "paths": {
- "/items/": {
- "get": {
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_items():
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.json() == [{"name": "Katana"}]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {
+ "title": "ChimichangApp",
+ "description": "\nChimichangApp API helps you do awesome stuff. 🚀\n\n## Items\n\nYou can **read items**.\n\n## Users\n\nYou will be able to:\n\n* **Create users** (_not implemented_).\n* **Read users** (_not implemented_).\n",
+ "termsOfService": "http://example.com/terms/",
+ "contact": {
+ "name": "Deadpoolio the Amazing",
+ "url": "http://x-force.example.com/contact/",
+ "email": "dp@x-force.example.com",
+ },
+ "license": {
+ "name": "Apache 2.0",
+ "url": "https://www.apache.org/licenses/LICENSE-2.0.html",
+ },
+ "version": "0.0.1",
+ },
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_metadata/test_tutorial004.py b/tests/test_tutorial/test_metadata/test_tutorial004.py
index 2d255b8b0..f7f47a558 100644
--- a/tests/test_tutorial/test_metadata/test_tutorial004.py
+++ b/tests/test_tutorial/test_metadata/test_tutorial004.py
@@ -4,62 +4,60 @@ from docs_src.metadata.tutorial004 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/users/": {
- "get": {
- "tags": ["users"],
- "summary": "Get Users",
- "operationId": "get_users_users__get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- }
- },
- "/items/": {
- "get": {
- "tags": ["items"],
- "summary": "Get Items",
- "operationId": "get_items_items__get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- }
- },
- },
- "tags": [
- {
- "name": "users",
- "description": "Operations with users. The **login** logic is also here.",
- },
- {
- "name": "items",
- "description": "Manage items. So _fancy_ they have their own docs.",
- "externalDocs": {
- "description": "Items external docs",
- "url": "https://fastapi.tiangolo.com/",
- },
- },
- ],
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_path_operations():
response = client.get("/items/")
assert response.status_code == 200, response.text
response = client.get("/users/")
assert response.status_code == 200, response.text
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/users/": {
+ "get": {
+ "tags": ["users"],
+ "summary": "Get Users",
+ "operationId": "get_users_users__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ },
+ "/items/": {
+ "get": {
+ "tags": ["items"],
+ "summary": "Get Items",
+ "operationId": "get_items_items__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ },
+ },
+ "tags": [
+ {
+ "name": "users",
+ "description": "Operations with users. The **login** logic is also here.",
+ },
+ {
+ "name": "items",
+ "description": "Manage items. So _fancy_ they have their own docs.",
+ "externalDocs": {
+ "description": "Items external docs",
+ "url": "https://fastapi.tiangolo.com/",
+ },
+ },
+ ],
+ }
diff --git a/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py b/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py
index e773e7f8f..c6cdc6064 100644
--- a/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py
+++ b/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py
@@ -4,171 +4,170 @@ from docs_src.openapi_callbacks.tutorial001 import app, invoice_notification
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/invoices/": {
- "post": {
- "summary": "Create Invoice",
- "description": 'Create an invoice.\n\nThis will (let\'s imagine) let the API user (some external developer) create an\ninvoice.\n\nAnd this path operation will:\n\n* Send the invoice to the client.\n* Collect the money from the client.\n* Send a notification back to the API user (the external developer), as a callback.\n * At this point is that the API will somehow send a POST request to the\n external API with the notification of the invoice event\n (e.g. "payment successful").',
- "operationId": "create_invoice_invoices__post",
- "parameters": [
- {
- "required": False,
- "schema": {
- "title": "Callback Url",
- "maxLength": 2083,
- "minLength": 1,
- "type": "string",
- "format": "uri",
- },
- "name": "callback_url",
- "in": "query",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Invoice"}
+
+def test_get():
+ response = client.post(
+ "/invoices/", json={"id": "fooinvoice", "customer": "John", "total": 5.3}
+ )
+ assert response.status_code == 200, response.text
+ assert response.json() == {"msg": "Invoice received"}
+
+
+def test_dummy_callback():
+ # Just for coverage
+ invoice_notification({})
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/invoices/": {
+ "post": {
+ "summary": "Create Invoice",
+ "description": 'Create an invoice.\n\nThis will (let\'s imagine) let the API user (some external developer) create an\ninvoice.\n\nAnd this path operation will:\n\n* Send the invoice to the client.\n* Collect the money from the client.\n* Send a notification back to the API user (the external developer), as a callback.\n * At this point is that the API will somehow send a POST request to the\n external API with the notification of the invoice event\n (e.g. "payment successful").',
+ "operationId": "create_invoice_invoices__post",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Callback Url",
+ "maxLength": 2083,
+ "minLength": 1,
+ "type": "string",
+ "format": "uri",
+ },
+ "name": "callback_url",
+ "in": "query",
}
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
+ ],
+ "requestBody": {
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
+ "schema": {"$ref": "#/components/schemas/Invoice"}
}
},
+ "required": True,
},
- },
- "callbacks": {
- "invoice_notification": {
- "{$callback_url}/invoices/{$request.body.id}": {
- "post": {
- "summary": "Invoice Notification",
- "operationId": "invoice_notification__callback_url__invoices___request_body_id__post",
- "requestBody": {
- "required": True,
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/InvoiceEvent"
- }
- }
- },
- },
- "responses": {
- "200": {
- "description": "Successful Response",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "callbacks": {
+ "invoice_notification": {
+ "{$callback_url}/invoices/{$request.body.id}": {
+ "post": {
+ "summary": "Invoice Notification",
+ "operationId": "invoice_notification__callback_url__invoices___request_body_id__post",
+ "requestBody": {
+ "required": True,
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/InvoiceEventReceived"
+ "$ref": "#/components/schemas/InvoiceEvent"
}
}
},
},
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InvoiceEventReceived"
+ }
}
- }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- },
+ }
}
}
- }
- },
+ },
+ }
}
- }
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
},
- },
- "Invoice": {
- "title": "Invoice",
- "required": ["id", "customer", "total"],
- "type": "object",
- "properties": {
- "id": {"title": "Id", "type": "string"},
- "title": {"title": "Title", "type": "string"},
- "customer": {"title": "Customer", "type": "string"},
- "total": {"title": "Total", "type": "number"},
+ "Invoice": {
+ "title": "Invoice",
+ "required": ["id", "customer", "total"],
+ "type": "object",
+ "properties": {
+ "id": {"title": "Id", "type": "string"},
+ "title": {"title": "Title", "type": "string"},
+ "customer": {"title": "Customer", "type": "string"},
+ "total": {"title": "Total", "type": "number"},
+ },
+ },
+ "InvoiceEvent": {
+ "title": "InvoiceEvent",
+ "required": ["description", "paid"],
+ "type": "object",
+ "properties": {
+ "description": {"title": "Description", "type": "string"},
+ "paid": {"title": "Paid", "type": "boolean"},
+ },
},
- },
- "InvoiceEvent": {
- "title": "InvoiceEvent",
- "required": ["description", "paid"],
- "type": "object",
- "properties": {
- "description": {"title": "Description", "type": "string"},
- "paid": {"title": "Paid", "type": "boolean"},
+ "InvoiceEventReceived": {
+ "title": "InvoiceEventReceived",
+ "required": ["ok"],
+ "type": "object",
+ "properties": {"ok": {"title": "Ok", "type": "boolean"}},
},
- },
- "InvoiceEventReceived": {
- "title": "InvoiceEventReceived",
- "required": ["ok"],
- "type": "object",
- "properties": {"ok": {"title": "Ok", "type": "boolean"}},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
},
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
},
- },
- }
- },
-}
-
-
-def test_openapi():
- with client:
- response = client.get("/openapi.json")
-
- assert response.json() == openapi_schema
-
-
-def test_get():
- response = client.post(
- "/invoices/", json={"id": "fooinvoice", "customer": "John", "total": 5.3}
- )
- assert response.status_code == 200, response.text
- assert response.json() == {"msg": "Invoice received"}
-
-
-def test_dummy_callback():
- # Just for coverage
- invoice_notification({})
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py
index 3b5301348..c1cdbee24 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py
@@ -4,33 +4,31 @@ from docs_src.path_operation_advanced_configuration.tutorial001 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Items",
- "operationId": "some_specific_id_you_define",
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get():
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.json() == [{"item_id": "Foo"}]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Items",
+ "operationId": "some_specific_id_you_define",
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py
index 01acb664c..fdaddd018 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py
@@ -4,33 +4,31 @@ from docs_src.path_operation_advanced_configuration.tutorial002 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Items",
- "operationId": "read_items",
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get():
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.json() == [{"item_id": "Foo"}]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Items",
+ "operationId": "read_items",
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py
index 4a23db7bc..782c64a84 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py
@@ -4,20 +4,18 @@ from docs_src.path_operation_advanced_configuration.tutorial003 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {},
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get():
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.json() == [{"item_id": "Foo"}]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {},
+ }
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py
index 3de19833b..f5fd868eb 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py
@@ -4,109 +4,109 @@ from docs_src.path_operation_advanced_configuration.tutorial004 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
+
+def test_query_params_str_validations():
+ response = client.post("/items/", json={"name": "Foo", "price": 42})
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "name": "Foo",
+ "price": 42,
+ "description": None,
+ "tax": None,
+ "tags": [],
+ }
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- "422": {
- "description": "Validation Error",
+ "summary": "Create an item",
+ "description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item",
+ "operationId": "create_item_items__post",
+ "requestBody": {
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
+ "required": True,
},
- },
- "summary": "Create an item",
- "description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item",
- "operationId": "create_item_items__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
+ }
}
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- "description": {"title": "Description", "type": "string"},
- "tax": {"title": "Tax", "type": "number"},
- "tags": {
- "title": "Tags",
- "uniqueItems": True,
- "type": "array",
- "items": {"type": "string"},
- "default": [],
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ "tags": {
+ "title": "Tags",
+ "uniqueItems": True,
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
},
},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
},
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
},
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
},
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
-def test_query_params_str_validations():
- response = client.post("/items/", json={"name": "Foo", "price": 42})
- assert response.status_code == 200, response.text
- assert response.json() == {
- "name": "Foo",
- "price": 42,
- "description": None,
- "tax": None,
- "tags": [],
+ }
+ },
}
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py
index 5042d1837..52379c01e 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py
@@ -4,33 +4,31 @@ from docs_src.path_operation_advanced_configuration.tutorial005 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "x-aperture-labs-portal": "blue",
- }
- }
- },
-}
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
+def test_get():
+ response = client.get("/items/")
assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-def test_get():
- response = client.get("/items/")
+def test_openapi_schema():
+ response = client.get("/openapi.json")
assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "x-aperture-labs-portal": "blue",
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py
index 330b4e2c7..deb6b0910 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py
@@ -4,47 +4,6 @@ from docs_src.path_operation_advanced_configuration.tutorial006 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "post": {
- "summary": "Create Item",
- "operationId": "create_item_items__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"type": "string"},
- "price": {"type": "number"},
- "description": {"type": "string"},
- },
- }
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_post():
response = client.post("/items/", content=b"this is actually not validated")
@@ -57,3 +16,42 @@ def test_post():
"description": "Just kiddin', no magic here. ✨",
},
}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "post": {
+ "summary": "Create Item",
+ "operationId": "create_item_items__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"type": "string"},
+ "price": {"type": "number"},
+ "description": {"type": "string"},
+ },
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py
index 076f60b2f..470956a77 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py
@@ -4,51 +4,6 @@ from docs_src.path_operation_advanced_configuration.tutorial007 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "post": {
- "summary": "Create Item",
- "operationId": "create_item_items__post",
- "requestBody": {
- "content": {
- "application/x-yaml": {
- "schema": {
- "title": "Item",
- "required": ["name", "tags"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "tags": {
- "title": "Tags",
- "type": "array",
- "items": {"type": "string"},
- },
- },
- }
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- }
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_post():
yaml_data = """
@@ -95,3 +50,46 @@ def test_post_invalid():
{"loc": ["tags", 3], "msg": "str type expected", "type": "type_error.str"}
]
}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "post": {
+ "summary": "Create Item",
+ "operationId": "create_item_items__post",
+ "requestBody": {
+ "content": {
+ "application/x-yaml": {
+ "schema": {
+ "title": "Item",
+ "required": ["name", "tags"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "tags": {
+ "title": "Tags",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ },
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py
index be9f2afec..76e44b5e5 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py
@@ -4,45 +4,6 @@ from docs_src.path_operation_configuration.tutorial002b import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "tags": ["items"],
- "summary": "Get Items",
- "operationId": "get_items_items__get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- }
- },
- "/users/": {
- "get": {
- "tags": ["users"],
- "summary": "Read Users",
- "operationId": "read_users_users__get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- }
- },
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_get_items():
response = client.get("/items/")
@@ -54,3 +15,40 @@ def test_get_users():
response = client.get("/users/")
assert response.status_code == 200, response.text
assert response.json() == ["Rick", "Morty"]
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "tags": ["items"],
+ "summary": "Get Items",
+ "operationId": "get_items_items__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ },
+ "/users/": {
+ "get": {
+ "tags": ["users"],
+ "summary": "Read Users",
+ "operationId": "read_users_users__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ },
+ },
+ }
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py
index e587519a0..cf8e203a0 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py
@@ -4,109 +4,109 @@ from docs_src.path_operation_configuration.tutorial005 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "post": {
- "responses": {
- "200": {
- "description": "The created item",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
+
+def test_query_params_str_validations():
+ response = client.post("/items/", json={"name": "Foo", "price": 42})
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "name": "Foo",
+ "price": 42,
+ "description": None,
+ "tax": None,
+ "tags": [],
+ }
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "The created item",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
},
},
- "422": {
- "description": "Validation Error",
+ "summary": "Create an item",
+ "description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item",
+ "operationId": "create_item_items__post",
+ "requestBody": {
"content": {
"application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
+ "schema": {"$ref": "#/components/schemas/Item"}
}
},
+ "required": True,
},
- },
- "summary": "Create an item",
- "description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item",
- "operationId": "create_item_items__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
+ }
}
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- "description": {"title": "Description", "type": "string"},
- "tax": {"title": "Tax", "type": "number"},
- "tags": {
- "title": "Tags",
- "uniqueItems": True,
- "type": "array",
- "items": {"type": "string"},
- "default": [],
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ "tags": {
+ "title": "Tags",
+ "uniqueItems": True,
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
},
},
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
},
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
},
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
},
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
-def test_query_params_str_validations():
- response = client.post("/items/", json={"name": "Foo", "price": 42})
- assert response.status_code == 200, response.text
- assert response.json() == {
- "name": "Foo",
- "price": 42,
- "description": None,
- "tax": None,
- "tags": [],
+ }
+ },
}
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py
index 43a7a610d..497fc9024 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py
@@ -3,95 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py310
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "post": {
- "responses": {
- "200": {
- "description": "The created item",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Create an item",
- "description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item",
- "operationId": "create_item_items__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- "description": {"title": "Description", "type": "string"},
- "tax": {"title": "Tax", "type": "number"},
- "tags": {
- "title": "Tags",
- "uniqueItems": True,
- "type": "array",
- "items": {"type": "string"},
- "default": [],
- },
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -101,13 +12,6 @@ def get_client():
return client
-@needs_py310
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
@needs_py310
def test_query_params_str_validations(client: TestClient):
response = client.post("/items/", json={"name": "Foo", "price": 42})
@@ -119,3 +23,99 @@ def test_query_params_str_validations(client: TestClient):
"tax": None,
"tags": [],
}
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "The created item",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create an item",
+ "description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item",
+ "operationId": "create_item_items__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ "tags": {
+ "title": "Tags",
+ "uniqueItems": True,
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py
index 62aa73ac5..09fac44c4 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py
@@ -3,95 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py39
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "post": {
- "responses": {
- "200": {
- "description": "The created item",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Create an item",
- "description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item",
- "operationId": "create_item_items__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/Item"}
- }
- },
- "required": True,
- },
- }
- }
- },
- "components": {
- "schemas": {
- "Item": {
- "title": "Item",
- "required": ["name", "price"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "price": {"title": "Price", "type": "number"},
- "description": {"title": "Description", "type": "string"},
- "tax": {"title": "Tax", "type": "number"},
- "tags": {
- "title": "Tags",
- "uniqueItems": True,
- "type": "array",
- "items": {"type": "string"},
- "default": [],
- },
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -101,13 +12,6 @@ def get_client():
return client
-@needs_py39
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
@needs_py39
def test_query_params_str_validations(client: TestClient):
response = client.post("/items/", json={"name": "Foo", "price": 42})
@@ -119,3 +23,99 @@ def test_query_params_str_validations(client: TestClient):
"tax": None,
"tags": [],
}
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "The created item",
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create an item",
+ "description": "Create an item with all the information:\n\n- **name**: each item must have a name\n- **description**: a long description\n- **price**: required\n- **tax**: if the item doesn't have tax, you can omit this\n- **tags**: a set of unique tag strings for this item",
+ "operationId": "create_item_items__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {"$ref": "#/components/schemas/Item"}
+ }
+ },
+ "required": True,
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Item": {
+ "title": "Item",
+ "required": ["name", "price"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "price": {"title": "Price", "type": "number"},
+ "description": {"title": "Description", "type": "string"},
+ "tax": {"title": "Tax", "type": "number"},
+ "tags": {
+ "title": "Tags",
+ "uniqueItems": True,
+ "type": "array",
+ "items": {"type": "string"},
+ "default": [],
+ },
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py
index 582caed44..e90771f24 100644
--- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py
+++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py
@@ -5,59 +5,6 @@ from docs_src.path_operation_configuration.tutorial006 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "tags": ["items"],
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- }
- },
- "/users/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "tags": ["users"],
- "summary": "Read Users",
- "operationId": "read_users_users__get",
- }
- },
- "/elements/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "tags": ["items"],
- "summary": "Read Elements",
- "operationId": "read_elements_elements__get",
- "deprecated": True,
- }
- },
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
@pytest.mark.parametrize(
"path,expected_status,expected_response",
@@ -71,3 +18,54 @@ def test_query_params_str_validations(path, expected_status, expected_response):
response = client.get(path)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "tags": ["items"],
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ }
+ },
+ "/users/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "tags": ["users"],
+ "summary": "Read Users",
+ "operationId": "read_users_users__get",
+ }
+ },
+ "/elements/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ "tags": ["items"],
+ "summary": "Read Elements",
+ "operationId": "read_elements_elements__get",
+ "deprecated": True,
+ }
+ },
+ },
+ }
diff --git a/tests/test_tutorial/test_path_params/test_tutorial004.py b/tests/test_tutorial/test_path_params/test_tutorial004.py
index 7f0227ecf..ab0455bf5 100644
--- a/tests/test_tutorial/test_path_params/test_tutorial004.py
+++ b/tests/test_tutorial/test_path_params/test_tutorial004.py
@@ -4,78 +4,6 @@ from docs_src.path_params.tutorial004 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/files/{file_path}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read File",
- "operationId": "read_file_files__file_path__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "File Path", "type": "string"},
- "name": "file_path",
- "in": "path",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_file_path():
response = client.get("/files/home/johndoe/myfile.txt")
@@ -89,3 +17,75 @@ def test_root_file_path():
print(response.content)
assert response.status_code == 200, response.text
assert response.json() == {"file_path": "/home/johndoe/myfile.txt"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/files/{file_path}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read File",
+ "operationId": "read_file_files__file_path__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "File Path", "type": "string"},
+ "name": "file_path",
+ "in": "path",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_path_params/test_tutorial005.py b/tests/test_tutorial/test_path_params/test_tutorial005.py
index eae3637be..3401f2253 100644
--- a/tests/test_tutorial/test_path_params/test_tutorial005.py
+++ b/tests/test_tutorial/test_path_params/test_tutorial005.py
@@ -5,156 +5,6 @@ from docs_src.path_params.tutorial005 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/models/{model_name}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Get Model",
- "operationId": "get_model_models__model_name__get",
- "parameters": [
- {
- "required": True,
- "schema": {
- "title": "Model Name",
- "enum": ["alexnet", "resnet", "lenet"],
- "type": "string",
- },
- "name": "model_name",
- "in": "path",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-openapi_schema2 = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/models/{model_name}": {
- "get": {
- "summary": "Get Model",
- "operationId": "get_model_models__model_name__get",
- "parameters": [
- {
- "required": True,
- "schema": {"$ref": "#/components/schemas/ModelName"},
- "name": "model_name",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "ModelName": {
- "title": "ModelName",
- "enum": ["alexnet", "resnet", "lenet"],
- "type": "string",
- "description": "An enumeration.",
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
-
-def test_openapi():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- data = response.json()
- assert data == openapi_schema or data == openapi_schema2
-
@pytest.mark.parametrize(
"url,status_code,expected",
@@ -194,3 +44,82 @@ def test_get_enums(url, status_code, expected):
response = client.get(url)
assert response.status_code == status_code
assert response.json() == expected
+
+
+def test_openapi():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ data = response.json()
+ assert data == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/models/{model_name}": {
+ "get": {
+ "summary": "Get Model",
+ "operationId": "get_model_models__model_name__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"$ref": "#/components/schemas/ModelName"},
+ "name": "model_name",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ModelName": {
+ "title": "ModelName",
+ "enum": ["alexnet", "resnet", "lenet"],
+ "type": "string",
+ "description": "An enumeration.",
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params/test_tutorial005.py b/tests/test_tutorial/test_query_params/test_tutorial005.py
index 07178f8a6..3c408449b 100644
--- a/tests/test_tutorial/test_query_params/test_tutorial005.py
+++ b/tests/test_tutorial/test_query_params/test_tutorial005.py
@@ -5,78 +5,6 @@ from docs_src.query_params.tutorial005 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read User Item",
- "operationId": "read_user_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- },
- {
- "required": True,
- "schema": {"title": "Needy", "type": "string"},
- "name": "needy",
- "in": "query",
- },
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
query_required = {
"detail": [
@@ -92,7 +20,6 @@ query_required = {
@pytest.mark.parametrize(
"path,expected_status,expected_response",
[
- ("/openapi.json", 200, openapi_schema),
("/items/foo?needy=very", 200, {"item_id": "foo", "needy": "very"}),
("/items/foo", 422, query_required),
("/items/foo", 422, query_required),
@@ -102,3 +29,81 @@ def test(path, expected_status, expected_response):
response = client.get(path)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read User Item",
+ "operationId": "read_user_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ },
+ {
+ "required": True,
+ "schema": {"title": "Needy", "type": "string"},
+ "name": "needy",
+ "in": "query",
+ },
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params/test_tutorial006.py b/tests/test_tutorial/test_query_params/test_tutorial006.py
index 73c5302e7..7fe58a990 100644
--- a/tests/test_tutorial/test_query_params/test_tutorial006.py
+++ b/tests/test_tutorial/test_query_params/test_tutorial006.py
@@ -5,90 +5,6 @@ from docs_src.query_params.tutorial006 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read User Item",
- "operationId": "read_user_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- },
- {
- "required": True,
- "schema": {"title": "Needy", "type": "string"},
- "name": "needy",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Skip", "type": "integer", "default": 0},
- "name": "skip",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Limit", "type": "integer"},
- "name": "limit",
- "in": "query",
- },
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
query_required = {
"detail": [
@@ -104,7 +20,6 @@ query_required = {
@pytest.mark.parametrize(
"path,expected_status,expected_response",
[
- ("/openapi.json", 200, openapi_schema),
(
"/items/foo?needy=very",
200,
@@ -139,3 +54,97 @@ def test(path, expected_status, expected_response):
response = client.get(path)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read User Item",
+ "operationId": "read_user_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ },
+ {
+ "required": True,
+ "schema": {"title": "Needy", "type": "string"},
+ "name": "needy",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {"title": "Limit", "type": "integer"},
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params/test_tutorial006_py310.py b/tests/test_tutorial/test_query_params/test_tutorial006_py310.py
index 141525f15..b90c0a6c8 100644
--- a/tests/test_tutorial/test_query_params/test_tutorial006_py310.py
+++ b/tests/test_tutorial/test_query_params/test_tutorial006_py310.py
@@ -3,91 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py310
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/{item_id}": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read User Item",
- "operationId": "read_user_item_items__item_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Item Id", "type": "string"},
- "name": "item_id",
- "in": "path",
- },
- {
- "required": True,
- "schema": {"title": "Needy", "type": "string"},
- "name": "needy",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Skip", "type": "integer", "default": 0},
- "name": "skip",
- "in": "query",
- },
- {
- "required": False,
- "schema": {"title": "Limit", "type": "integer"},
- "name": "limit",
- "in": "query",
- },
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
query_required = {
"detail": [
{
@@ -111,7 +26,6 @@ def get_client():
@pytest.mark.parametrize(
"path,expected_status,expected_response",
[
- ("/openapi.json", 200, openapi_schema),
(
"/items/foo?needy=very",
200,
@@ -146,3 +60,98 @@ def test(path, expected_status, expected_response, client: TestClient):
response = client.get(path)
assert response.status_code == expected_status
assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/{item_id}": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read User Item",
+ "operationId": "read_user_item_items__item_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Item Id", "type": "string"},
+ "name": "item_id",
+ "in": "path",
+ },
+ {
+ "required": True,
+ "schema": {"title": "Needy", "type": "string"},
+ "name": "needy",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Skip",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "skip",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {"title": "Limit", "type": "integer"},
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py
deleted file mode 100644
index f8d7f85c8..000000000
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py
+++ /dev/null
@@ -1,122 +0,0 @@
-import pytest
-from fastapi.testclient import TestClient
-
-from docs_src.query_params_str_validations.tutorial010 import app
-
-client = TestClient(app)
-
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "description": "Query string for the items to search in the database that have a good match",
- "required": False,
- "deprecated": True,
- "schema": {
- "title": "Query string",
- "maxLength": 50,
- "minLength": 3,
- "pattern": "^fixedquery$",
- "type": "string",
- "description": "Query string for the items to search in the database that have a good match",
- },
- "name": "item-query",
- "in": "query",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
-regex_error = {
- "detail": [
- {
- "ctx": {"pattern": "^fixedquery$"},
- "loc": ["query", "item-query"],
- "msg": 'string does not match regex "^fixedquery$"',
- "type": "value_error.str.regex",
- }
- ]
-}
-
-
-@pytest.mark.parametrize(
- "q_name,q,expected_status,expected_response",
- [
- (None, None, 200, {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}),
- (
- "item-query",
- "fixedquery",
- 200,
- {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}], "q": "fixedquery"},
- ),
- ("q", "fixedquery", 200, {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}),
- ("item-query", "nonregexquery", 422, regex_error),
- ],
-)
-def test_query_params_str_validations(q_name, q, expected_status, expected_response):
- url = "/items/"
- if q_name and q:
- url = f"{url}?{q_name}={q}"
- response = client.get(url)
- assert response.status_code == expected_status
- assert response.json() == expected_response
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial001_py310.py
deleted file mode 100644
index 298b5d616..000000000
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial001_py310.py
+++ /dev/null
@@ -1,132 +0,0 @@
-import pytest
-from fastapi.testclient import TestClient
-
-from ...utils import needs_py310
-
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "description": "Query string for the items to search in the database that have a good match",
- "required": False,
- "deprecated": True,
- "schema": {
- "title": "Query string",
- "maxLength": 50,
- "minLength": 3,
- "pattern": "^fixedquery$",
- "type": "string",
- "description": "Query string for the items to search in the database that have a good match",
- },
- "name": "item-query",
- "in": "query",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-@pytest.fixture(name="client")
-def get_client():
- from docs_src.query_params_str_validations.tutorial010_py310 import app
-
- client = TestClient(app)
- return client
-
-
-@needs_py310
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
-regex_error = {
- "detail": [
- {
- "ctx": {"pattern": "^fixedquery$"},
- "loc": ["query", "item-query"],
- "msg": 'string does not match regex "^fixedquery$"',
- "type": "value_error.str.regex",
- }
- ]
-}
-
-
-@needs_py310
-@pytest.mark.parametrize(
- "q_name,q,expected_status,expected_response",
- [
- (None, None, 200, {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}),
- (
- "item-query",
- "fixedquery",
- 200,
- {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}], "q": "fixedquery"},
- ),
- ("q", "fixedquery", 200, {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}),
- ("item-query", "nonregexquery", 422, regex_error),
- ],
-)
-def test_query_params_str_validations(
- q_name, q, expected_status, expected_response, client: TestClient
-):
- url = "/items/"
- if q_name and q:
- url = f"{url}?{q_name}={q}"
- response = client.get(url)
- assert response.status_code == expected_status
- assert response.json() == expected_response
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py
new file mode 100644
index 000000000..c41f554ba
--- /dev/null
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py
@@ -0,0 +1,122 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from docs_src.query_params_str_validations.tutorial010 import app
+
+client = TestClient(app)
+
+
+regex_error = {
+ "detail": [
+ {
+ "ctx": {"pattern": "^fixedquery$"},
+ "loc": ["query", "item-query"],
+ "msg": 'string does not match regex "^fixedquery$"',
+ "type": "value_error.str.regex",
+ }
+ ]
+}
+
+
+@pytest.mark.parametrize(
+ "q_name,q,expected_status,expected_response",
+ [
+ (None, None, 200, {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}),
+ (
+ "item-query",
+ "fixedquery",
+ 200,
+ {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}], "q": "fixedquery"},
+ ),
+ ("q", "fixedquery", 200, {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}),
+ ("item-query", "nonregexquery", 422, regex_error),
+ ],
+)
+def test_query_params_str_validations(q_name, q, expected_status, expected_response):
+ url = "/items/"
+ if q_name and q:
+ url = f"{url}?{q_name}={q}"
+ response = client.get(url)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "description": "Query string for the items to search in the database that have a good match",
+ "required": False,
+ "deprecated": True,
+ "schema": {
+ "title": "Query string",
+ "maxLength": 50,
+ "minLength": 3,
+ "pattern": "^fixedquery$",
+ "type": "string",
+ "description": "Query string for the items to search in the database that have a good match",
+ },
+ "name": "item-query",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an.py
new file mode 100644
index 000000000..dc8028f81
--- /dev/null
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an.py
@@ -0,0 +1,122 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from docs_src.query_params_str_validations.tutorial010_an import app
+
+client = TestClient(app)
+
+
+regex_error = {
+ "detail": [
+ {
+ "ctx": {"pattern": "^fixedquery$"},
+ "loc": ["query", "item-query"],
+ "msg": 'string does not match regex "^fixedquery$"',
+ "type": "value_error.str.regex",
+ }
+ ]
+}
+
+
+@pytest.mark.parametrize(
+ "q_name,q,expected_status,expected_response",
+ [
+ (None, None, 200, {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}),
+ (
+ "item-query",
+ "fixedquery",
+ 200,
+ {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}], "q": "fixedquery"},
+ ),
+ ("q", "fixedquery", 200, {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}),
+ ("item-query", "nonregexquery", 422, regex_error),
+ ],
+)
+def test_query_params_str_validations(q_name, q, expected_status, expected_response):
+ url = "/items/"
+ if q_name and q:
+ url = f"{url}?{q_name}={q}"
+ response = client.get(url)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "description": "Query string for the items to search in the database that have a good match",
+ "required": False,
+ "deprecated": True,
+ "schema": {
+ "title": "Query string",
+ "maxLength": 50,
+ "minLength": 3,
+ "pattern": "^fixedquery$",
+ "type": "string",
+ "description": "Query string for the items to search in the database that have a good match",
+ },
+ "name": "item-query",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py310.py
new file mode 100644
index 000000000..496b95b79
--- /dev/null
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py310.py
@@ -0,0 +1,132 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.query_params_str_validations.tutorial010_an_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+regex_error = {
+ "detail": [
+ {
+ "ctx": {"pattern": "^fixedquery$"},
+ "loc": ["query", "item-query"],
+ "msg": 'string does not match regex "^fixedquery$"',
+ "type": "value_error.str.regex",
+ }
+ ]
+}
+
+
+@needs_py310
+@pytest.mark.parametrize(
+ "q_name,q,expected_status,expected_response",
+ [
+ (None, None, 200, {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}),
+ (
+ "item-query",
+ "fixedquery",
+ 200,
+ {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}], "q": "fixedquery"},
+ ),
+ ("q", "fixedquery", 200, {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}),
+ ("item-query", "nonregexquery", 422, regex_error),
+ ],
+)
+def test_query_params_str_validations(
+ q_name, q, expected_status, expected_response, client: TestClient
+):
+ url = "/items/"
+ if q_name and q:
+ url = f"{url}?{q_name}={q}"
+ response = client.get(url)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "description": "Query string for the items to search in the database that have a good match",
+ "required": False,
+ "deprecated": True,
+ "schema": {
+ "title": "Query string",
+ "maxLength": 50,
+ "minLength": 3,
+ "pattern": "^fixedquery$",
+ "type": "string",
+ "description": "Query string for the items to search in the database that have a good match",
+ },
+ "name": "item-query",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py39.py
new file mode 100644
index 000000000..2005e5043
--- /dev/null
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py39.py
@@ -0,0 +1,132 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.query_params_str_validations.tutorial010_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+regex_error = {
+ "detail": [
+ {
+ "ctx": {"pattern": "^fixedquery$"},
+ "loc": ["query", "item-query"],
+ "msg": 'string does not match regex "^fixedquery$"',
+ "type": "value_error.str.regex",
+ }
+ ]
+}
+
+
+@needs_py39
+@pytest.mark.parametrize(
+ "q_name,q,expected_status,expected_response",
+ [
+ (None, None, 200, {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}),
+ (
+ "item-query",
+ "fixedquery",
+ 200,
+ {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}], "q": "fixedquery"},
+ ),
+ ("q", "fixedquery", 200, {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}),
+ ("item-query", "nonregexquery", 422, regex_error),
+ ],
+)
+def test_query_params_str_validations(
+ q_name, q, expected_status, expected_response, client: TestClient
+):
+ url = "/items/"
+ if q_name and q:
+ url = f"{url}?{q_name}={q}"
+ response = client.get(url)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "description": "Query string for the items to search in the database that have a good match",
+ "required": False,
+ "deprecated": True,
+ "schema": {
+ "title": "Query string",
+ "maxLength": 50,
+ "minLength": 3,
+ "pattern": "^fixedquery$",
+ "type": "string",
+ "description": "Query string for the items to search in the database that have a good match",
+ },
+ "name": "item-query",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_py310.py
new file mode 100644
index 000000000..8147d768e
--- /dev/null
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_py310.py
@@ -0,0 +1,132 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.query_params_str_validations.tutorial010_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+regex_error = {
+ "detail": [
+ {
+ "ctx": {"pattern": "^fixedquery$"},
+ "loc": ["query", "item-query"],
+ "msg": 'string does not match regex "^fixedquery$"',
+ "type": "value_error.str.regex",
+ }
+ ]
+}
+
+
+@needs_py310
+@pytest.mark.parametrize(
+ "q_name,q,expected_status,expected_response",
+ [
+ (None, None, 200, {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}),
+ (
+ "item-query",
+ "fixedquery",
+ 200,
+ {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}], "q": "fixedquery"},
+ ),
+ ("q", "fixedquery", 200, {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}),
+ ("item-query", "nonregexquery", 422, regex_error),
+ ],
+)
+def test_query_params_str_validations(
+ q_name, q, expected_status, expected_response, client: TestClient
+):
+ url = "/items/"
+ if q_name and q:
+ url = f"{url}?{q_name}={q}"
+ response = client.get(url)
+ assert response.status_code == expected_status
+ assert response.json() == expected_response
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "description": "Query string for the items to search in the database that have a good match",
+ "required": False,
+ "deprecated": True,
+ "schema": {
+ "title": "Query string",
+ "maxLength": 50,
+ "minLength": 3,
+ "pattern": "^fixedquery$",
+ "type": "string",
+ "description": "Query string for the items to search in the database that have a good match",
+ },
+ "name": "item-query",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py
index ad3645f31..d6d69c169 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py
@@ -4,82 +4,6 @@ from docs_src.query_params_str_validations.tutorial011 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": False,
- "schema": {
- "title": "Q",
- "type": "array",
- "items": {"type": "string"},
- },
- "name": "q",
- "in": "query",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_multi_query_values():
url = "/items/?q=foo&q=bar"
@@ -93,3 +17,79 @@ def test_query_no_values():
response = client.get(url)
assert response.status_code == 200, response.text
assert response.json() == {"q": None}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Q",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "name": "q",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an.py
new file mode 100644
index 000000000..3a53d422e
--- /dev/null
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an.py
@@ -0,0 +1,95 @@
+from fastapi.testclient import TestClient
+
+from docs_src.query_params_str_validations.tutorial011_an import app
+
+client = TestClient(app)
+
+
+def test_multi_query_values():
+ url = "/items/?q=foo&q=bar"
+ response = client.get(url)
+ assert response.status_code == 200, response.text
+ assert response.json() == {"q": ["foo", "bar"]}
+
+
+def test_query_no_values():
+ url = "/items/"
+ response = client.get(url)
+ assert response.status_code == 200, response.text
+ assert response.json() == {"q": None}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Q",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "name": "q",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an_py310.py
new file mode 100644
index 000000000..f00df2879
--- /dev/null
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an_py310.py
@@ -0,0 +1,105 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.query_params_str_validations.tutorial011_an_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py310
+def test_multi_query_values(client: TestClient):
+ url = "/items/?q=foo&q=bar"
+ response = client.get(url)
+ assert response.status_code == 200, response.text
+ assert response.json() == {"q": ["foo", "bar"]}
+
+
+@needs_py310
+def test_query_no_values(client: TestClient):
+ url = "/items/"
+ response = client.get(url)
+ assert response.status_code == 200, response.text
+ assert response.json() == {"q": None}
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Q",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "name": "q",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an_py39.py
new file mode 100644
index 000000000..895fb8e9f
--- /dev/null
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an_py39.py
@@ -0,0 +1,105 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.query_params_str_validations.tutorial011_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py39
+def test_multi_query_values(client: TestClient):
+ url = "/items/?q=foo&q=bar"
+ response = client.get(url)
+ assert response.status_code == 200, response.text
+ assert response.json() == {"q": ["foo", "bar"]}
+
+
+@needs_py39
+def test_query_no_values(client: TestClient):
+ url = "/items/"
+ response = client.get(url)
+ assert response.status_code == 200, response.text
+ assert response.json() == {"q": None}
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Q",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "name": "q",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py
index 9330037ed..4f4b1fd55 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py
@@ -3,76 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py310
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": False,
- "schema": {
- "title": "Q",
- "type": "array",
- "items": {"type": "string"},
- },
- "name": "q",
- "in": "query",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -82,13 +12,6 @@ def get_client():
return client
-@needs_py310
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
@needs_py310
def test_multi_query_values(client: TestClient):
url = "/items/?q=foo&q=bar"
@@ -103,3 +26,80 @@ def test_query_no_values(client: TestClient):
response = client.get(url)
assert response.status_code == 200, response.text
assert response.json() == {"q": None}
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Q",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "name": "q",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py
index 11f23be27..d85bb6231 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py
@@ -3,76 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py39
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": False,
- "schema": {
- "title": "Q",
- "type": "array",
- "items": {"type": "string"},
- },
- "name": "q",
- "in": "query",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -82,13 +12,6 @@ def get_client():
return client
-@needs_py39
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
@needs_py39
def test_multi_query_values(client: TestClient):
url = "/items/?q=foo&q=bar"
@@ -103,3 +26,80 @@ def test_query_no_values(client: TestClient):
response = client.get(url)
assert response.status_code == 200, response.text
assert response.json() == {"q": None}
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Q",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "name": "q",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py
index d69139dda..7bc020540 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py
@@ -4,83 +4,6 @@ from docs_src.query_params_str_validations.tutorial012 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": False,
- "schema": {
- "title": "Q",
- "type": "array",
- "items": {"type": "string"},
- "default": ["foo", "bar"],
- },
- "name": "q",
- "in": "query",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_default_query_values():
url = "/items/"
@@ -94,3 +17,80 @@ def test_multi_query_values():
response = client.get(url)
assert response.status_code == 200, response.text
assert response.json() == {"q": ["baz", "foobar"]}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Q",
+ "type": "array",
+ "items": {"type": "string"},
+ "default": ["foo", "bar"],
+ },
+ "name": "q",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_an.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_an.py
new file mode 100644
index 000000000..be5557f6a
--- /dev/null
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_an.py
@@ -0,0 +1,96 @@
+from fastapi.testclient import TestClient
+
+from docs_src.query_params_str_validations.tutorial012_an import app
+
+client = TestClient(app)
+
+
+def test_default_query_values():
+ url = "/items/"
+ response = client.get(url)
+ assert response.status_code == 200, response.text
+ assert response.json() == {"q": ["foo", "bar"]}
+
+
+def test_multi_query_values():
+ url = "/items/?q=baz&q=foobar"
+ response = client.get(url)
+ assert response.status_code == 200, response.text
+ assert response.json() == {"q": ["baz", "foobar"]}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Q",
+ "type": "array",
+ "items": {"type": "string"},
+ "default": ["foo", "bar"],
+ },
+ "name": "q",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_an_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_an_py39.py
new file mode 100644
index 000000000..d9512e193
--- /dev/null
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_an_py39.py
@@ -0,0 +1,106 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.query_params_str_validations.tutorial012_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py39
+def test_default_query_values(client: TestClient):
+ url = "/items/"
+ response = client.get(url)
+ assert response.status_code == 200, response.text
+ assert response.json() == {"q": ["foo", "bar"]}
+
+
+@needs_py39
+def test_multi_query_values(client: TestClient):
+ url = "/items/?q=baz&q=foobar"
+ response = client.get(url)
+ assert response.status_code == 200, response.text
+ assert response.json() == {"q": ["baz", "foobar"]}
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Q",
+ "type": "array",
+ "items": {"type": "string"},
+ "default": ["foo", "bar"],
+ },
+ "name": "q",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py
index b25bb2847..b2a2c8d1d 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py
@@ -3,77 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py39
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": False,
- "schema": {
- "title": "Q",
- "type": "array",
- "items": {"type": "string"},
- "default": ["foo", "bar"],
- },
- "name": "q",
- "in": "query",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -83,13 +12,6 @@ def get_client():
return client
-@needs_py39
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
@needs_py39
def test_default_query_values(client: TestClient):
url = "/items/"
@@ -104,3 +26,81 @@ def test_multi_query_values(client: TestClient):
response = client.get(url)
assert response.status_code == 200, response.text
assert response.json() == {"q": ["baz", "foobar"]}
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Q",
+ "type": "array",
+ "items": {"type": "string"},
+ "default": ["foo", "bar"],
+ },
+ "name": "q",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py
index 1b2e36354..4a0b9e8b5 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py
@@ -4,83 +4,6 @@ from docs_src.query_params_str_validations.tutorial013 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "parameters": [
- {
- "required": False,
- "schema": {
- "title": "Q",
- "type": "array",
- "items": {},
- "default": [],
- },
- "name": "q",
- "in": "query",
- }
- ],
- }
- }
- },
- "components": {
- "schemas": {
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_multi_query_values():
url = "/items/?q=foo&q=bar"
@@ -94,3 +17,80 @@ def test_query_no_values():
response = client.get(url)
assert response.status_code == 200, response.text
assert response.json() == {"q": []}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Q",
+ "type": "array",
+ "items": {},
+ "default": [],
+ },
+ "name": "q",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013_an.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013_an.py
new file mode 100644
index 000000000..71e4638ae
--- /dev/null
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013_an.py
@@ -0,0 +1,96 @@
+from fastapi.testclient import TestClient
+
+from docs_src.query_params_str_validations.tutorial013_an import app
+
+client = TestClient(app)
+
+
+def test_multi_query_values():
+ url = "/items/?q=foo&q=bar"
+ response = client.get(url)
+ assert response.status_code == 200, response.text
+ assert response.json() == {"q": ["foo", "bar"]}
+
+
+def test_query_no_values():
+ url = "/items/"
+ response = client.get(url)
+ assert response.status_code == 200, response.text
+ assert response.json() == {"q": []}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Q",
+ "type": "array",
+ "items": {},
+ "default": [],
+ },
+ "name": "q",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013_an_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013_an_py39.py
new file mode 100644
index 000000000..4e90db358
--- /dev/null
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013_an_py39.py
@@ -0,0 +1,106 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.query_params_str_validations.tutorial013_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py39
+def test_multi_query_values(client: TestClient):
+ url = "/items/?q=foo&q=bar"
+ response = client.get(url)
+ assert response.status_code == 200, response.text
+ assert response.json() == {"q": ["foo", "bar"]}
+
+
+@needs_py39
+def test_query_no_values(client: TestClient):
+ url = "/items/"
+ response = client.get(url)
+ assert response.status_code == 200, response.text
+ assert response.json() == {"q": []}
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Q",
+ "type": "array",
+ "items": {},
+ "default": [],
+ },
+ "name": "q",
+ "in": "query",
+ }
+ ],
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py
index 57b8b9d94..7686c07b3 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py
@@ -5,71 +5,6 @@ from docs_src.query_params_str_validations.tutorial014 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
def test_hidden_query():
response = client.get("/items?hidden_query=somevalue")
assert response.status_code == 200, response.text
@@ -80,3 +15,67 @@ def test_no_hidden_query():
response = client.get("/items")
assert response.status_code == 200, response.text
assert response.json() == {"hidden_query": "Not found"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an.py
new file mode 100644
index 000000000..e739044a8
--- /dev/null
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an.py
@@ -0,0 +1,81 @@
+from fastapi.testclient import TestClient
+
+from docs_src.query_params_str_validations.tutorial014_an import app
+
+client = TestClient(app)
+
+
+def test_hidden_query():
+ response = client.get("/items?hidden_query=somevalue")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"hidden_query": "somevalue"}
+
+
+def test_no_hidden_query():
+ response = client.get("/items")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"hidden_query": "Not found"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an_py310.py
new file mode 100644
index 000000000..73f0ba78b
--- /dev/null
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an_py310.py
@@ -0,0 +1,91 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.query_params_str_validations.tutorial014_an_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py310
+def test_hidden_query(client: TestClient):
+ response = client.get("/items?hidden_query=somevalue")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"hidden_query": "somevalue"}
+
+
+@needs_py310
+def test_no_hidden_query(client: TestClient):
+ response = client.get("/items")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"hidden_query": "Not found"}
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an_py39.py
new file mode 100644
index 000000000..e2c149992
--- /dev/null
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an_py39.py
@@ -0,0 +1,91 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.query_params_str_validations.tutorial014_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py310
+def test_hidden_query(client: TestClient):
+ response = client.get("/items?hidden_query=somevalue")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"hidden_query": "somevalue"}
+
+
+@needs_py310
+def test_no_hidden_query(client: TestClient):
+ response = client.get("/items")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"hidden_query": "Not found"}
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py
index fe54fc080..07f30b739 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py
@@ -3,64 +3,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py310
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/items/": {
- "get": {
- "summary": "Read Items",
- "operationId": "read_items_items__get",
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- }
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -70,13 +12,6 @@ def get_client():
return client
-@needs_py310
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
@needs_py310
def test_hidden_query(client: TestClient):
response = client.get("/items?hidden_query=somevalue")
@@ -89,3 +24,68 @@ def test_no_hidden_query(client: TestClient):
response = client.get("/items")
assert response.status_code == 200, response.text
assert response.json() == {"hidden_query": "Not found"}
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001.py b/tests/test_tutorial/test_request_files/test_tutorial001.py
index 166014c71..3269801ef 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial001.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial001.py
@@ -4,128 +4,6 @@ from docs_src.request_files.tutorial001 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/files/": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Create File",
- "operationId": "create_file_files__post",
- "requestBody": {
- "content": {
- "multipart/form-data": {
- "schema": {
- "$ref": "#/components/schemas/Body_create_file_files__post"
- }
- }
- },
- "required": True,
- },
- }
- },
- "/uploadfile/": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Create Upload File",
- "operationId": "create_upload_file_uploadfile__post",
- "requestBody": {
- "content": {
- "multipart/form-data": {
- "schema": {
- "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post"
- }
- }
- },
- "required": True,
- },
- }
- },
- },
- "components": {
- "schemas": {
- "Body_create_upload_file_uploadfile__post": {
- "title": "Body_create_upload_file_uploadfile__post",
- "required": ["file"],
- "type": "object",
- "properties": {
- "file": {"title": "File", "type": "string", "format": "binary"}
- },
- },
- "Body_create_file_files__post": {
- "title": "Body_create_file_files__post",
- "required": ["file"],
- "type": "object",
- "properties": {
- "file": {"title": "File", "type": "string", "format": "binary"}
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
file_required = {
"detail": [
@@ -182,3 +60,125 @@ def test_post_upload_file(tmp_path):
response = client.post("/uploadfile/", files={"file": file})
assert response.status_code == 200, response.text
assert response.json() == {"filename": "test.txt"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/files/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create File",
+ "operationId": "create_file_files__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_file_files__post"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ },
+ "/uploadfile/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create Upload File",
+ "operationId": "create_upload_file_uploadfile__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_create_upload_file_uploadfile__post": {
+ "title": "Body_create_upload_file_uploadfile__post",
+ "required": ["file"],
+ "type": "object",
+ "properties": {
+ "file": {"title": "File", "type": "string", "format": "binary"}
+ },
+ },
+ "Body_create_file_files__post": {
+ "title": "Body_create_file_files__post",
+ "required": ["file"],
+ "type": "object",
+ "properties": {
+ "file": {"title": "File", "type": "string", "format": "binary"}
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02.py b/tests/test_tutorial/test_request_files/test_tutorial001_02.py
index a254bf3e8..4b6edfa06 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial001_02.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_02.py
@@ -4,124 +4,6 @@ from docs_src.request_files.tutorial001_02 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/files/": {
- "post": {
- "summary": "Create File",
- "operationId": "create_file_files__post",
- "requestBody": {
- "content": {
- "multipart/form-data": {
- "schema": {
- "$ref": "#/components/schemas/Body_create_file_files__post"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- "/uploadfile/": {
- "post": {
- "summary": "Create Upload File",
- "operationId": "create_upload_file_uploadfile__post",
- "requestBody": {
- "content": {
- "multipart/form-data": {
- "schema": {
- "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- },
- "components": {
- "schemas": {
- "Body_create_file_files__post": {
- "title": "Body_create_file_files__post",
- "type": "object",
- "properties": {
- "file": {"title": "File", "type": "string", "format": "binary"}
- },
- },
- "Body_create_upload_file_uploadfile__post": {
- "title": "Body_create_upload_file_uploadfile__post",
- "type": "object",
- "properties": {
- "file": {"title": "File", "type": "string", "format": "binary"}
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_post_form_no_body():
response = client.post("/files/")
@@ -155,3 +37,121 @@ def test_post_upload_file(tmp_path):
response = client.post("/uploadfile/", files={"file": file})
assert response.status_code == 200, response.text
assert response.json() == {"filename": "test.txt"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/files/": {
+ "post": {
+ "summary": "Create File",
+ "operationId": "create_file_files__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_file_files__post"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/uploadfile/": {
+ "post": {
+ "summary": "Create Upload File",
+ "operationId": "create_upload_file_uploadfile__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_create_file_files__post": {
+ "title": "Body_create_file_files__post",
+ "type": "object",
+ "properties": {
+ "file": {"title": "File", "type": "string", "format": "binary"}
+ },
+ },
+ "Body_create_upload_file_uploadfile__post": {
+ "title": "Body_create_upload_file_uploadfile__post",
+ "type": "object",
+ "properties": {
+ "file": {"title": "File", "type": "string", "format": "binary"}
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02_an.py b/tests/test_tutorial/test_request_files/test_tutorial001_02_an.py
new file mode 100644
index 000000000..0c34620e3
--- /dev/null
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_02_an.py
@@ -0,0 +1,157 @@
+from fastapi.testclient import TestClient
+
+from docs_src.request_files.tutorial001_02_an import app
+
+client = TestClient(app)
+
+
+def test_post_form_no_body():
+ response = client.post("/files/")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"message": "No file sent"}
+
+
+def test_post_uploadfile_no_body():
+ response = client.post("/uploadfile/")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"message": "No upload file sent"}
+
+
+def test_post_file(tmp_path):
+ path = tmp_path / "test.txt"
+ path.write_bytes(b"")
+
+ client = TestClient(app)
+ with path.open("rb") as file:
+ response = client.post("/files/", files={"file": file})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"file_size": 14}
+
+
+def test_post_upload_file(tmp_path):
+ path = tmp_path / "test.txt"
+ path.write_bytes(b"")
+
+ client = TestClient(app)
+ with path.open("rb") as file:
+ response = client.post("/uploadfile/", files={"file": file})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"filename": "test.txt"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/files/": {
+ "post": {
+ "summary": "Create File",
+ "operationId": "create_file_files__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_file_files__post"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/uploadfile/": {
+ "post": {
+ "summary": "Create Upload File",
+ "operationId": "create_upload_file_uploadfile__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_create_file_files__post": {
+ "title": "Body_create_file_files__post",
+ "type": "object",
+ "properties": {
+ "file": {"title": "File", "type": "string", "format": "binary"}
+ },
+ },
+ "Body_create_upload_file_uploadfile__post": {
+ "title": "Body_create_upload_file_uploadfile__post",
+ "type": "object",
+ "properties": {
+ "file": {"title": "File", "type": "string", "format": "binary"}
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02_an_py310.py b/tests/test_tutorial/test_request_files/test_tutorial001_02_an_py310.py
new file mode 100644
index 000000000..04442c76f
--- /dev/null
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_02_an_py310.py
@@ -0,0 +1,169 @@
+from pathlib import Path
+
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py310
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.request_files.tutorial001_02_an_py310 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py310
+def test_post_form_no_body(client: TestClient):
+ response = client.post("/files/")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"message": "No file sent"}
+
+
+@needs_py310
+def test_post_uploadfile_no_body(client: TestClient):
+ response = client.post("/uploadfile/")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"message": "No upload file sent"}
+
+
+@needs_py310
+def test_post_file(tmp_path: Path, client: TestClient):
+ path = tmp_path / "test.txt"
+ path.write_bytes(b"")
+
+ with path.open("rb") as file:
+ response = client.post("/files/", files={"file": file})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"file_size": 14}
+
+
+@needs_py310
+def test_post_upload_file(tmp_path: Path, client: TestClient):
+ path = tmp_path / "test.txt"
+ path.write_bytes(b"")
+
+ with path.open("rb") as file:
+ response = client.post("/uploadfile/", files={"file": file})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"filename": "test.txt"}
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/files/": {
+ "post": {
+ "summary": "Create File",
+ "operationId": "create_file_files__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_file_files__post"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/uploadfile/": {
+ "post": {
+ "summary": "Create Upload File",
+ "operationId": "create_upload_file_uploadfile__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_create_file_files__post": {
+ "title": "Body_create_file_files__post",
+ "type": "object",
+ "properties": {
+ "file": {"title": "File", "type": "string", "format": "binary"}
+ },
+ },
+ "Body_create_upload_file_uploadfile__post": {
+ "title": "Body_create_upload_file_uploadfile__post",
+ "type": "object",
+ "properties": {
+ "file": {"title": "File", "type": "string", "format": "binary"}
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02_an_py39.py b/tests/test_tutorial/test_request_files/test_tutorial001_02_an_py39.py
new file mode 100644
index 000000000..f5249ef5b
--- /dev/null
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_02_an_py39.py
@@ -0,0 +1,169 @@
+from pathlib import Path
+
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.request_files.tutorial001_02_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py39
+def test_post_form_no_body(client: TestClient):
+ response = client.post("/files/")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"message": "No file sent"}
+
+
+@needs_py39
+def test_post_uploadfile_no_body(client: TestClient):
+ response = client.post("/uploadfile/")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"message": "No upload file sent"}
+
+
+@needs_py39
+def test_post_file(tmp_path: Path, client: TestClient):
+ path = tmp_path / "test.txt"
+ path.write_bytes(b"")
+
+ with path.open("rb") as file:
+ response = client.post("/files/", files={"file": file})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"file_size": 14}
+
+
+@needs_py39
+def test_post_upload_file(tmp_path: Path, client: TestClient):
+ path = tmp_path / "test.txt"
+ path.write_bytes(b"")
+
+ with path.open("rb") as file:
+ response = client.post("/uploadfile/", files={"file": file})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"filename": "test.txt"}
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/files/": {
+ "post": {
+ "summary": "Create File",
+ "operationId": "create_file_files__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_file_files__post"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/uploadfile/": {
+ "post": {
+ "summary": "Create Upload File",
+ "operationId": "create_upload_file_uploadfile__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_create_file_files__post": {
+ "title": "Body_create_file_files__post",
+ "type": "object",
+ "properties": {
+ "file": {"title": "File", "type": "string", "format": "binary"}
+ },
+ },
+ "Body_create_upload_file_uploadfile__post": {
+ "title": "Body_create_upload_file_uploadfile__post",
+ "type": "object",
+ "properties": {
+ "file": {"title": "File", "type": "string", "format": "binary"}
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py b/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py
index 15b6a8d53..f690d107b 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py
@@ -5,118 +5,6 @@ from fastapi.testclient import TestClient
from ...utils import needs_py310
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/files/": {
- "post": {
- "summary": "Create File",
- "operationId": "create_file_files__post",
- "requestBody": {
- "content": {
- "multipart/form-data": {
- "schema": {
- "$ref": "#/components/schemas/Body_create_file_files__post"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- "/uploadfile/": {
- "post": {
- "summary": "Create Upload File",
- "operationId": "create_upload_file_uploadfile__post",
- "requestBody": {
- "content": {
- "multipart/form-data": {
- "schema": {
- "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- },
- "components": {
- "schemas": {
- "Body_create_file_files__post": {
- "title": "Body_create_file_files__post",
- "type": "object",
- "properties": {
- "file": {"title": "File", "type": "string", "format": "binary"}
- },
- },
- "Body_create_upload_file_uploadfile__post": {
- "title": "Body_create_upload_file_uploadfile__post",
- "type": "object",
- "properties": {
- "file": {"title": "File", "type": "string", "format": "binary"}
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
@pytest.fixture(name="client")
def get_client():
@@ -126,13 +14,6 @@ def get_client():
return client
-@needs_py310
-def test_openapi_schema(client: TestClient):
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
-
@needs_py310
def test_post_form_no_body(client: TestClient):
response = client.post("/files/")
@@ -167,3 +48,122 @@ def test_post_upload_file(tmp_path: Path, client: TestClient):
response = client.post("/uploadfile/", files={"file": file})
assert response.status_code == 200, response.text
assert response.json() == {"filename": "test.txt"}
+
+
+@needs_py310
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/files/": {
+ "post": {
+ "summary": "Create File",
+ "operationId": "create_file_files__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_file_files__post"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/uploadfile/": {
+ "post": {
+ "summary": "Create Upload File",
+ "operationId": "create_upload_file_uploadfile__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_create_file_files__post": {
+ "title": "Body_create_file_files__post",
+ "type": "object",
+ "properties": {
+ "file": {"title": "File", "type": "string", "format": "binary"}
+ },
+ },
+ "Body_create_upload_file_uploadfile__post": {
+ "title": "Body_create_upload_file_uploadfile__post",
+ "type": "object",
+ "properties": {
+ "file": {"title": "File", "type": "string", "format": "binary"}
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_03.py b/tests/test_tutorial/test_request_files/test_tutorial001_03.py
index c34165f18..4af659a11 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial001_03.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_03.py
@@ -4,138 +4,6 @@ from docs_src.request_files.tutorial001_03 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/files/": {
- "post": {
- "summary": "Create File",
- "operationId": "create_file_files__post",
- "requestBody": {
- "content": {
- "multipart/form-data": {
- "schema": {
- "$ref": "#/components/schemas/Body_create_file_files__post"
- }
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- "/uploadfile/": {
- "post": {
- "summary": "Create Upload File",
- "operationId": "create_upload_file_uploadfile__post",
- "requestBody": {
- "content": {
- "multipart/form-data": {
- "schema": {
- "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post"
- }
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- },
- "components": {
- "schemas": {
- "Body_create_file_files__post": {
- "title": "Body_create_file_files__post",
- "required": ["file"],
- "type": "object",
- "properties": {
- "file": {
- "title": "File",
- "type": "string",
- "description": "A file read as bytes",
- "format": "binary",
- }
- },
- },
- "Body_create_upload_file_uploadfile__post": {
- "title": "Body_create_upload_file_uploadfile__post",
- "required": ["file"],
- "type": "object",
- "properties": {
- "file": {
- "title": "File",
- "type": "string",
- "description": "A file read as UploadFile",
- "format": "binary",
- }
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
def test_post_file(tmp_path):
path = tmp_path / "test.txt"
@@ -157,3 +25,135 @@ def test_post_upload_file(tmp_path):
response = client.post("/uploadfile/", files={"file": file})
assert response.status_code == 200, response.text
assert response.json() == {"filename": "test.txt"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/files/": {
+ "post": {
+ "summary": "Create File",
+ "operationId": "create_file_files__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_file_files__post"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/uploadfile/": {
+ "post": {
+ "summary": "Create Upload File",
+ "operationId": "create_upload_file_uploadfile__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_create_file_files__post": {
+ "title": "Body_create_file_files__post",
+ "required": ["file"],
+ "type": "object",
+ "properties": {
+ "file": {
+ "title": "File",
+ "type": "string",
+ "description": "A file read as bytes",
+ "format": "binary",
+ }
+ },
+ },
+ "Body_create_upload_file_uploadfile__post": {
+ "title": "Body_create_upload_file_uploadfile__post",
+ "required": ["file"],
+ "type": "object",
+ "properties": {
+ "file": {
+ "title": "File",
+ "type": "string",
+ "description": "A file read as UploadFile",
+ "format": "binary",
+ }
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_03_an.py b/tests/test_tutorial/test_request_files/test_tutorial001_03_an.py
new file mode 100644
index 000000000..91dbc60b9
--- /dev/null
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_03_an.py
@@ -0,0 +1,159 @@
+from fastapi.testclient import TestClient
+
+from docs_src.request_files.tutorial001_03_an import app
+
+client = TestClient(app)
+
+
+def test_post_file(tmp_path):
+ path = tmp_path / "test.txt"
+ path.write_bytes(b"")
+
+ client = TestClient(app)
+ with path.open("rb") as file:
+ response = client.post("/files/", files={"file": file})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"file_size": 14}
+
+
+def test_post_upload_file(tmp_path):
+ path = tmp_path / "test.txt"
+ path.write_bytes(b"")
+
+ client = TestClient(app)
+ with path.open("rb") as file:
+ response = client.post("/uploadfile/", files={"file": file})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"filename": "test.txt"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/files/": {
+ "post": {
+ "summary": "Create File",
+ "operationId": "create_file_files__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_file_files__post"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/uploadfile/": {
+ "post": {
+ "summary": "Create Upload File",
+ "operationId": "create_upload_file_uploadfile__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_create_file_files__post": {
+ "title": "Body_create_file_files__post",
+ "required": ["file"],
+ "type": "object",
+ "properties": {
+ "file": {
+ "title": "File",
+ "type": "string",
+ "description": "A file read as bytes",
+ "format": "binary",
+ }
+ },
+ },
+ "Body_create_upload_file_uploadfile__post": {
+ "title": "Body_create_upload_file_uploadfile__post",
+ "required": ["file"],
+ "type": "object",
+ "properties": {
+ "file": {
+ "title": "File",
+ "type": "string",
+ "description": "A file read as UploadFile",
+ "format": "binary",
+ }
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_03_an_py39.py b/tests/test_tutorial/test_request_files/test_tutorial001_03_an_py39.py
new file mode 100644
index 000000000..7c4ad326c
--- /dev/null
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_03_an_py39.py
@@ -0,0 +1,167 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.request_files.tutorial001_03_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py39
+def test_post_file(tmp_path, client: TestClient):
+ path = tmp_path / "test.txt"
+ path.write_bytes(b"")
+
+ with path.open("rb") as file:
+ response = client.post("/files/", files={"file": file})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"file_size": 14}
+
+
+@needs_py39
+def test_post_upload_file(tmp_path, client: TestClient):
+ path = tmp_path / "test.txt"
+ path.write_bytes(b"")
+
+ with path.open("rb") as file:
+ response = client.post("/uploadfile/", files={"file": file})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"filename": "test.txt"}
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/files/": {
+ "post": {
+ "summary": "Create File",
+ "operationId": "create_file_files__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_file_files__post"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/uploadfile/": {
+ "post": {
+ "summary": "Create Upload File",
+ "operationId": "create_upload_file_uploadfile__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_create_file_files__post": {
+ "title": "Body_create_file_files__post",
+ "required": ["file"],
+ "type": "object",
+ "properties": {
+ "file": {
+ "title": "File",
+ "type": "string",
+ "description": "A file read as bytes",
+ "format": "binary",
+ }
+ },
+ },
+ "Body_create_upload_file_uploadfile__post": {
+ "title": "Body_create_upload_file_uploadfile__post",
+ "required": ["file"],
+ "type": "object",
+ "properties": {
+ "file": {
+ "title": "File",
+ "type": "string",
+ "description": "A file read as UploadFile",
+ "format": "binary",
+ }
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_an.py b/tests/test_tutorial/test_request_files/test_tutorial001_an.py
new file mode 100644
index 000000000..80c288ed6
--- /dev/null
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_an.py
@@ -0,0 +1,184 @@
+from fastapi.testclient import TestClient
+
+from docs_src.request_files.tutorial001_an import app
+
+client = TestClient(app)
+
+
+file_required = {
+ "detail": [
+ {
+ "loc": ["body", "file"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ }
+ ]
+}
+
+
+def test_post_form_no_body():
+ response = client.post("/files/")
+ assert response.status_code == 422, response.text
+ assert response.json() == file_required
+
+
+def test_post_body_json():
+ response = client.post("/files/", json={"file": "Foo"})
+ assert response.status_code == 422, response.text
+ assert response.json() == file_required
+
+
+def test_post_file(tmp_path):
+ path = tmp_path / "test.txt"
+ path.write_bytes(b"")
+
+ client = TestClient(app)
+ with path.open("rb") as file:
+ response = client.post("/files/", files={"file": file})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"file_size": 14}
+
+
+def test_post_large_file(tmp_path):
+ default_pydantic_max_size = 2**16
+ path = tmp_path / "test.txt"
+ path.write_bytes(b"x" * (default_pydantic_max_size + 1))
+
+ client = TestClient(app)
+ with path.open("rb") as file:
+ response = client.post("/files/", files={"file": file})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"file_size": default_pydantic_max_size + 1}
+
+
+def test_post_upload_file(tmp_path):
+ path = tmp_path / "test.txt"
+ path.write_bytes(b"")
+
+ client = TestClient(app)
+ with path.open("rb") as file:
+ response = client.post("/uploadfile/", files={"file": file})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"filename": "test.txt"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/files/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create File",
+ "operationId": "create_file_files__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_file_files__post"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ },
+ "/uploadfile/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create Upload File",
+ "operationId": "create_upload_file_uploadfile__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_create_upload_file_uploadfile__post": {
+ "title": "Body_create_upload_file_uploadfile__post",
+ "required": ["file"],
+ "type": "object",
+ "properties": {
+ "file": {"title": "File", "type": "string", "format": "binary"}
+ },
+ },
+ "Body_create_file_files__post": {
+ "title": "Body_create_file_files__post",
+ "required": ["file"],
+ "type": "object",
+ "properties": {
+ "file": {"title": "File", "type": "string", "format": "binary"}
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_an_py39.py b/tests/test_tutorial/test_request_files/test_tutorial001_an_py39.py
new file mode 100644
index 000000000..4dc1f752c
--- /dev/null
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_an_py39.py
@@ -0,0 +1,194 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.request_files.tutorial001_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+file_required = {
+ "detail": [
+ {
+ "loc": ["body", "file"],
+ "msg": "field required",
+ "type": "value_error.missing",
+ }
+ ]
+}
+
+
+@needs_py39
+def test_post_form_no_body(client: TestClient):
+ response = client.post("/files/")
+ assert response.status_code == 422, response.text
+ assert response.json() == file_required
+
+
+@needs_py39
+def test_post_body_json(client: TestClient):
+ response = client.post("/files/", json={"file": "Foo"})
+ assert response.status_code == 422, response.text
+ assert response.json() == file_required
+
+
+@needs_py39
+def test_post_file(tmp_path, client: TestClient):
+ path = tmp_path / "test.txt"
+ path.write_bytes(b"")
+
+ with path.open("rb") as file:
+ response = client.post("/files/", files={"file": file})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"file_size": 14}
+
+
+@needs_py39
+def test_post_large_file(tmp_path, client: TestClient):
+ default_pydantic_max_size = 2**16
+ path = tmp_path / "test.txt"
+ path.write_bytes(b"x" * (default_pydantic_max_size + 1))
+
+ with path.open("rb") as file:
+ response = client.post("/files/", files={"file": file})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"file_size": default_pydantic_max_size + 1}
+
+
+@needs_py39
+def test_post_upload_file(tmp_path, client: TestClient):
+ path = tmp_path / "test.txt"
+ path.write_bytes(b"")
+
+ with path.open("rb") as file:
+ response = client.post("/uploadfile/", files={"file": file})
+ assert response.status_code == 200, response.text
+ assert response.json() == {"filename": "test.txt"}
+
+
+@needs_py39
+def test_openapi_schema(client: TestClient):
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/files/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create File",
+ "operationId": "create_file_files__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_file_files__post"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ },
+ "/uploadfile/": {
+ "post": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ "summary": "Create Upload File",
+ "operationId": "create_upload_file_uploadfile__post",
+ "requestBody": {
+ "content": {
+ "multipart/form-data": {
+ "schema": {
+ "$ref": "#/components/schemas/Body_create_upload_file_uploadfile__post"
+ }
+ }
+ },
+ "required": True,
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "Body_create_upload_file_uploadfile__post": {
+ "title": "Body_create_upload_file_uploadfile__post",
+ "required": ["file"],
+ "type": "object",
+ "properties": {
+ "file": {"title": "File", "type": "string", "format": "binary"}
+ },
+ },
+ "Body_create_file_files__post": {
+ "title": "Body_create_file_files__post",
+ "required": ["file"],
+ "type": "object",
+ "properties": {
+ "file": {"title": "File", "type": "string", "format": "binary"}
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "anyOf": [{"type": "string"}, {"type": "integer"}]
+ },
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/ValidationError"},
+ }
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_request_files/test_tutorial002.py b/tests/test_tutorial/test_request_files/test_tutorial002.py
index 73d1179a1..6868be328 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial002.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial002.py
@@ -4,148 +4,6 @@ from docs_src.request_files.tutorial002 import app
client = TestClient(app)
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/files/": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Create Files",
- "operationId": "create_files_files__post",
- "requestBody": {
- "content": {
- "multipart/form-data": {
- "schema": {
- "$ref": "#/components/schemas/Body_create_files_files__post"
- }
- }
- },
- "required": True,
- },
- }
- },
- "/uploadfiles/": {
- "post": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- "summary": "Create Upload Files",
- "operationId": "create_upload_files_uploadfiles__post",
- "requestBody": {
- "content": {
- "multipart/form-data": {
- "schema": {
- "$ref": "#/components/schemas/Body_create_upload_files_uploadfiles__post"
- }
- }
- },
- "required": True,
- },
- }
- },
- "/": {
- "get": {
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- }
- },
- "summary": "Main",
- "operationId": "main__get",
- }
- },
- },
- "components": {
- "schemas": {
- "Body_create_upload_files_uploadfiles__post": {
- "title": "Body_create_upload_files_uploadfiles__post",
- "required": ["files"],
- "type": "object",
- "properties": {
- "files": {
- "title": "Files",
- "type": "array",
- "items": {"type": "string", "format": "binary"},
- }
- },
- },
- "Body_create_files_files__post": {
- "title": "Body_create_files_files__post",
- "required": ["files"],
- "type": "object",
- "properties": {
- "files": {
- "title": "Files",
- "type": "array",
- "items": {"type": "string", "format": "binary"},
- }
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- }
- },
-}
-
-
-def test_openapi_schema():
- response = client.get("/openapi.json")
- assert response.status_code == 200, response.text
- assert response.json() == openapi_schema
-
file_required = {
"detail": [
@@ -213,3 +71,145 @@ def test_get_root():
response = client.get("/")
assert response.status_code == 200, response.text
assert b"