```console
-$ pip install -e ."[dev,doc,test]"
+$ pip install -r requirements.txt
---> 100%
```
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
. 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
.
+
+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
.
+
+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
, 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
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
, 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
.
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, то есть подсказки типов), объединить их.
+
+## Предшествующие инструменты
+
+###
+
+Это самый популярный Python-фреймворк, и он пользуется доверием.
+Он используется для создания проектов типа Instagram.
+
+Django довольно тесно связан с реляционными базами данных (такими как MySQL или PostgreSQL), потому использовать NoSQL базы данных (например, Couchbase, MongoDB, Cassandra и т.п.) в качестве основного хранилища данных - непросто.
+
+Он был создан для генерации HTML-страниц на сервере, а не для создания API, используемых современными веб-интерфейсами (React, Vue.js, Angular и т.п.) или другими системами (например,
+
+Фреймворк Django REST был создан, как гибкий инструментарий для создания веб-API на основе Django.
+
+DRF использовался многими компаниями, включая Mozilla, Red Hat и Eventbrite.
+
+Это был один из первых примеров **автоматического документирования API** и это была одна из первых идей, вдохновивших на создание **FastAPI**.
+
+!!! note "Заметка"
+ Django REST Framework был создан Tom Christie.
+ Он же создал Starlette и Uvicorn, на которых основан **FastAPI**.
+
+!!! check "Идея для **FastAPI**"
+ Должно быть автоматическое создание документации API с пользовательским веб-интерфейсом.
+
+###
+
+Flask - это "микрофреймворк", в нём нет интеграции с базами данных и многих других вещей, которые предустановлены в Django.
+
+Его простота и гибкость дают широкие возможности, такие как использование баз данных NoSQL в качестве основной системы хранения данных.
+
+Он очень прост, его изучение интуитивно понятно, хотя в некоторых местах документация довольно техническая.
+
+Flask часто используется и для приложений, которым не нужна база данных, настройки прав доступа для пользователей и прочие из множества функций, предварительно встроенных в Django.
+Хотя многие из этих функций могут быть добавлены с помощью плагинов.
+
+Такое разделение на части и то, что это "микрофреймворк", который можно расширить, добавляя необходимые возможности, было ключевой особенностью, которую я хотел сохранить.
+
+Простота Flask, показалась мне подходящей для создания API.
+Но ещё нужно было найти "Django REST Framework" для Flask.
+
+!!! check "Идеи для **FastAPI**"
+ Это будет микрофреймворк. К нему легко будет добавить необходимые инструменты и части.
+
+ Должна быть простая и лёгкая в использовании система маршрутизации запросов.
+
+
+###
+
+На самом деле **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-методов (операций) для упрощения понимания происходящего.
+ * Должны быть разумные настройки по умолчанию и широкие возможности их кастомизации.
+
+
+###
+
+Главной функцией, которую я хотел унаследовать от Django REST Framework, была автоматическая документация API.
+
+Но потом я обнаружил, что существует стандарт документирования API, использующий JSON (или YAML, расширение JSON) под названием Swagger.
+
+И к нему уже был создан пользовательский веб-интерфейс.
+Таким образом, возможность генерировать документацию Swagger для API позволила бы использовать этот интерфейс.
+
+В какой-то момент Swagger был передан Linux Foundation и переименован в OpenAPI.
+
+Вот почему, когда говорят о версии 2.0, обычно говорят "Swagger", а для версии 3+ "OpenAPI".
+
+!!! check "Идеи для **FastAPI**"
+ Использовать открытые стандарты для спецификаций API вместо самодельных схем.
+
+ Совместимость с основанными на стандартах пользовательскими интерфейсами:
+
+ *
+
+ Они были выбраны за популярность и стабильность.
+ Но сделав беглый поиск, Вы можете найти десятки альтернативных пользовательских интерфейсов для OpenAPI, которые Вы можете использовать с **FastAPI**.
+
+### REST фреймворки для Flask
+
+Существует несколько REST фреймворков для Flask, но потратив время и усилия на их изучение, я обнаружил, что многие из них не обновляются или заброшены и имеют нерешённые проблемы из-за которых они непригодны к использованию.
+
+###
" данных, то есть преобразование данных из кода (Python) во что-то, что может быть отправлено по сети.
+Например, превращение объекта содержащего данные из базы данных в объект JSON, конвертация объекта `datetime` в строку и т.п.
+
+Еще одна важная функция, необходимая API — проверка данных, позволяющая убедиться, что данные действительны и соответствуют заданным параметрам.
+Как пример, можно указать, что ожидаются данные типа `int`, а не какая-то произвольная строка.
+Это особенно полезно для входящих данных.
+
+Без системы проверки данных Вам пришлось бы прописывать все проверки вручную.
+
+Именно для обеспечения этих функций и была создана Marshmallow.
+Это отличная библиотека и я много раз пользовался ею раньше.
+
+Но она была создана до того, как появились подсказки типов Python.
+Итак, чтобы определить каждую
,
+Вам нужно использовать определенные утилиты и классы, предоставляемые Marshmallow.
+
+!!! check "Идея для **FastAPI**"
+ Использовать код программы для автоматического создания "схем", определяющих типы данных и их проверку.
+
+###
данных из входящих запросов.
+
+Webargs - это инструмент, который был создан для этого и поддерживает несколько фреймворков, включая Flask.
+
+Для проверки данных он использует Marshmallow и создан теми же авторами.
+
+Это превосходный инструмент и я тоже часто пользовался им до **FastAPI**.
+
+!!! info "Информация"
+ Webargs бы создан разработчиками Marshmallow.
+
+!!! check "Идея для **FastAPI**"
+ Должна быть автоматическая проверка входных данных.
+
+###
+
+Marshmallow и Webargs осуществляют проверку, анализ и сериализацию данных как плагины.
+
+Но документации API всё ещё не было. Тогда был создан APISpec.
+
+Это плагин для множества фреймворков, в том числе и для Starlette.
+
+Он работает так - Вы записываете определение схем, используя формат YAML, внутри докстринга каждой функции, обрабатывающей маршрут.
+
+Используя эти докстринги, он генерирует схему OpenAPI.
+
+Так это работает для Flask, Starlette, Responder и т.п.
+
+Но теперь у нас возникает новая проблема - наличие постороннего микро-синтаксиса внутри кода Python (большие YAML).
+
+Редактор кода не особо может помочь в такой парадигме.
+А изменив какие-то параметры или схемы для Marshmallow можно забыть отредактировать докстринг с YAML и сгенерированная схема становится недействительной.
+
+!!! info "Информация"
+ APISpec тоже был создан авторами Marshmallow.
+
+!!! check "Идея для **FastAPI**"
+ Необходима поддержка открытого стандарта для API - OpenAPI.
+
+###
+
+Это плагин для Flask, который связан с Webargs, Marshmallow и APISpec.
+
+Он получает информацию от Webargs и Marshmallow, а затем использует APISpec для автоматического создания схемы OpenAPI.
+
+Это отличный, но крайне недооценённый инструмент.
+Он должен быть более популярен, чем многие плагины для Flask.
+Возможно, это связано с тем, что его документация слишком скудна и абстрактна.
+
+Он избавил от необходимости писать чужеродный синтаксис YAML внутри докстрингов.
+
+Такое сочетание Flask, Flask-apispec, Marshmallow и Webargs было моим любимым стеком при построении бэкенда до появления **FastAPI**.
+
+Использование этого стека привело к созданию нескольких генераторов проектов. Я и некоторые другие команды до сих пор используем их:
+
+*
+
+Эти генераторы проектов также стали основой для [Генераторов проектов с **FastAPI**](project-generation.md){.internal-link target=_blank}.
+
+!!! info "Информация"
+ Как ни странно, но Flask-apispec тоже создан авторами Marshmallow.
+
+!!! check "Идея для **FastAPI**"
+ Схема OpenAPI должна создаваться автоматически и использовать тот же код, который осуществляет сериализацию и проверку данных.
+
+###
)
+
+Здесь даже не используется Python. NestJS - этот фреймворк написанный на JavaScript (TypeScript), основанный на NodeJS и вдохновлённый Angular.
+
+Он позволяет получить нечто похожее на то, что можно сделать с помощью Flask-apispec.
+
+В него встроена система внедрения зависимостей, ещё одна идея взятая от Angular.
+Однако требуется предварительная регистрация "внедрений" (как и во всех других известных мне системах внедрения зависимостей), что увеличивает количество и повторяемость кода.
+
+Так как параметры в нём описываются с помощью типов TypeScript (аналогично подсказкам типов в Python), поддержка редактора работает довольно хорошо.
+
+Но поскольку данные из TypeScript не сохраняются после компиляции в JavaScript, он не может полагаться на подсказки типов для определения проверки данных, сериализации и документации.
+Из-за этого и некоторых дизайнерских решений, для валидации, сериализации и автоматической генерации схем, приходится во многих местах добавлять декораторы.
+Таким образом, это становится довольно многословным.
+
+Кроме того, он не очень хорошо справляется с вложенными моделями.
+Если в запросе имеется объект JSON, внутренние поля которого, в свою очередь, являются вложенными объектами JSON, это не может быть должным образом задокументировано и проверено.
+
+!!! check "Идеи для **FastAPI** "
+ Нужно использовать подсказки типов, чтоб воспользоваться поддержкой редактора кода.
+
+ Нужна мощная система внедрения зависимостей. Необходим способ для уменьшения повторов кода.
+
+###
+
+Sanic был одним из первых чрезвычайно быстрых Python-фреймворков основанных на `asyncio`.
+Он был сделан очень похожим на Flask.
+
+!!! note "Технические детали"
+ В нём использован
вместо стандартного цикла событий `asyncio`, что и сделало его таким быстрым.
+
+ Он явно вдохновил создателей Uvicorn и Starlette, которые в настоящее время быстрее Sanic в открытых бенчмарках.
+
+!!! check "Идеи для **FastAPI**"
+ Должна быть сумасшедшая производительность.
+
+ Для этого **FastAPI** основан на Starlette, самом быстром из доступных фреймворков (по замерам незаинтересованных лиц).
+
+###
+
+Falcon - ещё один высокопроизводительный Python-фреймворк.
+В нём минимум функций и он создан, чтоб быть основой для других фреймворков, например, Hug.
+
+Функции в нём получают два параметра - "запрос к серверу" и "ответ сервера".
+Затем Вы "читаете" часть запроса и "пишите" часть ответа.
+Из-за такой конструкции невозможно объявить параметры запроса и тела сообщения со стандартными подсказками типов Python в качестве параметров функции.
+
+Таким образом, и валидацию данных, и их сериализацию, и документацию нужно прописывать вручную.
+Либо эти функции должны быть встроены во фреймворк, сконструированный поверх Falcon, как в Hug.
+Такая же особенность присутствует и в других фреймворках, вдохновлённых идеей Falcon, использовать только один объект запроса и один объект ответа.
+
+!!! check "Идея для **FastAPI**"
+ Найдите способы добиться отличной производительности.
+
+ Объявлять параметры `ответа сервера` в функциях, как в Hug.
+
+ Хотя в FastAPI это необязательно и используется в основном для установки заголовков, куки и альтернативных кодов состояния.
+
+###
+
+Molten мне попался на начальной стадии написания **FastAPI**. В нём были похожие идеи:
+
+* Использование подсказок типов.
+* Валидация и документация исходя из этих подсказок.
+* Система внедрения зависимостей.
+
+В нём не используются сторонние библиотеки (такие, как Pydantic) для валидации, сериализации и документации.
+Поэтому переиспользовать эти определения типов непросто.
+
+Также требуется более подробная конфигурация и используется стандарт WSGI, который не предназначен для использования с высокопроизводительными инструментами, такими как Uvicorn, Starlette и Sanic, в отличие от ASGI.
+
+Его система внедрения зависимостей требует предварительной регистрации, и зависимости определяются, как объявления типов.
+Из-за этого невозможно объявить более одного "компонента" (зависимости), который предоставляет определенный тип.
+
+Маршруты объявляются в единственном месте с использованием функций, объявленных в других местах (вместо использования декораторов, в которые могут быть обёрнуты функции, обрабатывающие конкретные ресурсы).
+Это больше похоже на Django, чем на Flask и Starlette.
+Он разделяет в коде вещи, которые довольно тесно связаны.
+
+!!! check "Идея для **FastAPI**"
+ Определить дополнительные проверки типов данных, используя значения атрибутов модели "по умолчанию".
+ Это улучшает помощь редактора и раньше это не было доступно в Pydantic.
+
+ Фактически это подтолкнуло на обновление Pydantic для поддержки одинакового стиля проверок (теперь этот функционал уже доступен в Pydantic).
+
+###
+
+Hug был одним из первых фреймворков, реализовавших объявление параметров API с использованием подсказок типов Python.
+Эта отличная идея была использована и другими инструментами.
+
+При объявлении параметров вместо стандартных типов Python использовались собственные типы, но всё же это был огромный шаг вперед.
+
+Это также был один из первых фреймворков, генерировавших полную API-схему в формате JSON.
+
+Данная схема не придерживалась стандартов вроде OpenAPI и JSON Schema.
+Поэтому было бы непросто совместить её с другими инструментами, такими как Swagger UI.
+Но опять же, это была очень инновационная идея.
+
+Ещё у него есть интересная и необычная функция: используя один и тот же фреймворк можно создавать и API, и
.
+
+Поскольку он основан на WSGI, старом стандарте для синхронных веб-фреймворков, он не может работать с веб-сокетами и другими модными штуками, но всё равно обладает высокой производительностью.
+
+!!! info "Информация"
+ Hug создан Timothy Crosley, автором
, отличного инструмента для автоматической сортировки импортов в Python-файлах.
+
+!!! check "Идеи для **FastAPI**"
+ Hug повлиял на создание некоторых частей APIStar и был одним из инструментов, которые я счел наиболее многообещающими, наряду с APIStar.
+
+ Hug натолкнул на мысли использовать в **FastAPI** подсказки типов Python для автоматического создания схемы, определяющей API и его параметры.
+
+ Hug вдохновил **FastAPI** объявить параметр `ответа` в функциях для установки заголовков и куки.
+
+###
(<= 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 - это библиотека для валидации данных, сериализации и документирования (используя JSON Schema), основываясь на подсказках типов Python, что делает его чрезвычайно интуитивным.
+
+Его можно сравнить с Marshmallow, хотя в бенчмарках Pydantic быстрее, чем Marshmallow.
+И он основан на тех же подсказках типов, которые отлично поддерживаются редакторами кода.
+
+!!! check "**FastAPI** использует Pydantic"
+ Для проверки данных, сериализации данных и автоматической документации моделей (на основе JSON Schema).
+
+ Затем **FastAPI** берёт эти схемы JSON и помещает их в схему OpenAPI, не касаясь других вещей, которые он делает.
+
+###
фреймворк/набор инструментов, который идеален для построения высокопроизводительных асинхронных сервисов.
+
+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 - это молниеносный 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
и уступает только 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..f9b8912e5
--- /dev/null
+++ b/docs/ru/docs/contributing.md
@@ -0,0 +1,469 @@
+# Участие в разработке фреймворка
+
+Возможно, для начала Вам стоит ознакомиться с основными способами [помочь FastAPI или получить помощь](help-fastapi.md){.internal-link target=_blank}.
+
+## Разработка
+
+Если Вы уже склонировали репозиторий и знаете, что Вам нужно более глубокое погружение в код фреймворка, то здесь представлены некоторые инструкции по настройке виртуального окружения.
+
+### Виртуальное окружение с помощью `venv`
+
+Находясь в нужной директории, Вы можете создать виртуальное окружение при помощи Python модуля `venv`.
+
+
+
+Эта команда создаст директорию `./env/` с бинарными (двоичными) файлами Python, а затем Вы сможете скачивать и устанавливать необходимые библиотеки в изолированное виртуальное окружение.
+
+### Активация виртуального окружения
+
+Активируйте виртуально окружение командой:
+
+=== "Linux, macOS"
+
+
+
+ ```console
+ $ which pip
+
+ some/directory/fastapi/env/bin/pip
+ ```
+
+
+
+ ```console
+ $ Get-Command pip
+
+ some/directory/fastapi/env/bin/pip
+ ```
+
+
+
+Если в терминале появится ответ, что бинарник `pip` расположен по пути `.../env/bin/pip`, значит всё в порядке. 🎉
+
+Во избежание ошибок в дальнейших шагах, удостоверьтесь, что в Вашем виртуальном окружении установлена последняя версия `pip`:
+
+
+
+!!! tip "Подсказка"
+ Каждый раз, перед установкой новой библиотеки в виртуальное окружение при помощи `pip`, не забудьте активировать это виртуальное окружение.
+
+ Это гарантирует, что если Вы используете библиотеку, установленную этим пакетом, то Вы используете библиотеку из Вашего локального окружения, а не любую другую, которая может быть установлена глобально.
+
+### pip
+
+После активации виртуального окружения, как было указано ранее, введите следующую команду:
+
+
+
+Это установит все необходимые зависимости в локальное окружение для Вашего локального FastAPI.
+
+#### Использование локального FastAPI
+
+Если Вы создаёте Python файл, который импортирует и использует FastAPI,а затем запускаете его интерпретатором Python из Вашего локального окружения, то он будет использовать код из локального FastAPI.
+
+И, так как при вводе вышеупомянутой команды был указан флаг `-e`, если Вы измените код локального FastAPI, то при следующем запуске этого файла, он будет использовать свежую версию локального FastAPI, который Вы только что изменили.
+
+Таким образом, Вам не нужно "переустанавливать" Вашу локальную версию, чтобы протестировать каждое изменение.
+
+### Форматировние
+
+Скачанный репозиторий содержит скрипт, который может отформатировать и подчистить Ваш код:
+
+
+
+Заодно он упорядочит Ваши импорты.
+
+Чтобы он сортировал их правильно, необходимо, чтобы FastAPI был установлен локально в Вашей среде, с помощью команды из раздела выше, использующей флаг `-e`.
+
+## Документация
+
+Прежде всего, убедитесь, что Вы настроили своё окружение, как описано выше, для установки всех зависимостей.
+
+Документация использует
.
+
+Также существуют дополнительные инструменты/скрипты для работы с переводами в `./scripts/docs.py`.
+
+!!! tip "Подсказка"
+
+ Нет необходимости заглядывать в `./scripts/docs.py`, просто используйте это в командной строке.
+
+Вся документация имеет формат Markdown и расположена в директории `./docs/en/`.
+
+Многие руководства содержат блоки кода.
+
+В большинстве случаев эти блоки кода представляют собой вполне законченные приложения, которые можно запускать как есть.
+
+На самом деле, эти блоки кода не написаны внутри Markdown, это Python файлы в директории `./docs_src/`.
+
+И эти Python файлы включаются/вводятся в документацию при создании сайта.
+
+### Тестирование документации
+
+
+Фактически, большинство тестов запускаются с примерами исходных файлов в документации.
+
+Это помогает убедиться, что:
+
+* Документация находится в актуальном состоянии.
+* Примеры из документации могут быть запущены как есть.
+* Большинство функций описаны в документации и покрыты тестами.
+
+Существует скрипт, который во время локальной разработки создаёт сайт и проверяет наличие любых изменений, перезагружая его в реальном времени:
+
+
+
+Он запустит сайт документации по адресу: `http://127.0.0.1:8008`.
+
+
+Таким образом, Вы сможете редактировать файлы с документацией или кодом и наблюдать изменения вживую.
+
+#### Typer CLI (опционально)
+
+
+Приведенная ранее инструкция показала Вам, как запускать скрипт `./scripts/docs.py` непосредственно через интерпретатор `python` .
+
+Но также можно использовать
, что позволит Вам воспользоваться автозаполнением команд в Вашем терминале.
+
+Если Вы установили Typer CLI, то для включения функции автозаполнения, введите эту команду:
+
+
+
+```console
+$ typer --install-completion
+
+zsh completion installed in /home/user/.bashrc.
+Completion will take effect once you restart the terminal.
+```
+
+
+
+### Приложения и документация одновременно
+
+Если Вы запускаете приложение, например так:
+
+
+
+По умолчанию Uvicorn будет использовать порт `8000` и не будет конфликтовать с сайтом документации, использующим порт `8008`.
+
+### Переводы на другие языки
+
+Помощь с переводами ценится КРАЙНЕ ВЫСОКО! И переводы не могут быть сделаны без помощи сообщества. 🌎 🚀
+
+Ниже приведены шаги, как помочь с переводами.
+
+#### Подсказки и инструкции
+
+* Проверьте
для Вашего языка. Добавьте отзывы с просьбой внести изменения, если они необходимы, или одобрите их.
+
+!!! tip "Подсказка"
+ Вы можете
, чтобы узнать, есть ли кто-то, координирующий переводы для Вашего языка.
+
+* Добавляйте один пул-реквест для каждой отдельной переведённой страницы. Это значительно облегчит другим его просмотр.
+
+Для языков, которые я не знаю, прежде чем добавить перевод в основную ветку, я подожду пока несколько других участников сообщества проверят его.
+
+* Вы также можете проверить, есть ли переводы для Вашего языка и добавить к ним отзыв, который поможет мне убедиться в правильности перевода. Тогда я смогу объединить его с основной веткой.
+
+* Используйте те же самые примеры кода Python. Переводите только текст документации. Вам не нужно ничего менять, чтобы эти примеры работали.
+
+* Используйте те же самые изображения, имена файлов и ссылки. Вы не должны менять ничего для сохранения работоспособности.
+
+* Чтобы узнать 2-буквенный код языка, на который Вы хотите сделать перевод, Вы можете воспользоваться таблицей
.
+
+#### Существующий язык
+
+Допустим, Вы хотите перевести страницу на язык, на котором уже есть какие-то переводы, например, на испанский.
+
+Кодом испанского языка является `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
+```
+
+
и наблюдать вносимые Вами изменения вживую.
+
+
+Если Вы посмотрите на сайт документации 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:
+
+
+
+Эта команда создаст директорию `./htmlcov/`, в которой будет файл `./htmlcov/index.html`. Открыв его в Вашем браузере, Вы можете в интерактивном режиме изучить, все ли части кода охвачены тестами.
diff --git a/docs/ru/docs/deployment/concepts.md b/docs/ru/docs/deployment/concepts.md
new file mode 100644
index 000000000..681acf15e
--- /dev/null
+++ b/docs/ru/docs/deployment/concepts.md
@@ -0,0 +1,311 @@
+# Концепции развёртывания
+
+Существует несколько концепций, применяемых для развёртывания приложений **FastAPI**, равно как и для любых других типов веб-приложений, среди которых Вы можете выбрать **наиболее подходящий** способ.
+
+Самые важные из них:
+
+* Использование более безопасного протокола HTTPS
+* Настройки запуска приложения
+* Перезагрузка приложения
+* Запуск нескольких экземпляров приложения
+* Управление памятью
+* Использование перечисленных функций перед запуском приложения.
+
+Рассмотрим ниже влияние каждого из них на процесс **развёртывания**.
+
+Наша конечная цель - **обслуживать клиентов Вашего API безопасно** и **бесперебойно**, с максимально эффективным использованием **вычислительных ресурсов** (например, удалённых серверов/виртуальных машин). 🚀
+
+Здесь я немного расскажу Вам об этих **концепциях** и надеюсь, что у Вас сложится **интуитивное понимание**, какой способ выбрать при развертывании Вашего API в различных окружениях, возможно, даже **ещё не существующих**.
+
+Ознакомившись с этими концепциями, Вы сможете **оценить и выбрать** лучший способ развёртывании **Вашего API**.
+
+В последующих главах я предоставлю Вам **конкретные рецепты** развёртывания приложения FastAPI.
+
+А сейчас давайте остановимся на важных **идеях этих концепций**. Эти идеи можно также применить и к другим типам веб-приложений. 💡
+
+## Использование более безопасного протокола HTTPS
+
+В [предыдущей главе об HTTPS](./https.md){.internal-link target=_blank} мы рассмотрели, как HTTPS обеспечивает шифрование для Вашего API.
+
+Также мы заметили, что обычно для работы с HTTPS Вашему приложению нужен **дополнительный** компонент - **прокси-сервер завершения работы TLS**.
+
+И если прокси-сервер не умеет сам **обновлять сертификаты HTTPS**, то нужен ещё один компонент для этого действия.
+
+### Примеры инструментов для работы с HTTPS
+
+Вот некоторые инструменты, которые Вы можете применять как прокси-серверы:
+
+* Traefik
+ * С автоматическим обновлением сертификатов ✨
+* Caddy
+ * С автоматическим обновлением сертификатов ✨
+* Nginx
+ * С дополнительным компонентом типа Certbot для обновления сертификатов
+* HAProxy
+ * С дополнительным компонентом типа Certbot для обновления сертификатов
+* Kubernetes с Ingress Controller похожим на Nginx
+ * С дополнительным компонентом типа cert-manager для обновления сертификатов
+* Использование услуг облачного провайдера (читайте ниже 👇)
+
+В последнем варианте Вы можете воспользоваться услугами **облачного сервиса**, который сделает большую часть работы, включая настройку HTTPS. Это может наложить дополнительные ограничения или потребовать дополнительную плату и т.п. Зато Вам не понадобится самостоятельно заниматься настройками прокси-сервера.
+
+В дальнейшем я покажу Вам некоторые конкретные примеры их применения.
+
+---
+
+Следующие концепции рассматривают применение программы, запускающей Ваш API (такой как Uvicorn).
+
+## Программа и процесс
+
+Мы часто будем встречать слова **процесс** и **программа**, потому следует уяснить отличия между ними.
+
+### Что такое программа
+
+Термином **программа** обычно описывают множество вещей:
+
+* **Код**, который Вы написали, в нашем случае **Python-файлы**.
+* **Файл**, который может быть **исполнен** операционной системой, например `python`, `python.exe` или `uvicorn`.
+* Конкретная программа, **запущенная** операционной системой и использующая центральный процессор и память. В таком случае это также называется **процесс**.
+
+### Что такое процесс
+
+Термин **процесс** имеет более узкое толкование, подразумевая что-то, запущенное операционной системой (как в последнем пункте из вышестоящего абзаца):
+
+* Конкретная программа, **запущенная** операционной системой.
+ * Это не имеет отношения к какому-либо файлу или коду, но нечто **определённое**, управляемое и **выполняемое** операционной системой.
+* Любая программа, любой код, **могут делать что-то** только когда они **выполняются**. То есть, когда являются **работающим процессом**.
+* Процесс может быть **прерван** (или "убит") Вами или Вашей операционной системой. В результате чего он перестанет исполняться и **не будет продолжать делать что-либо**.
+* Каждое приложение, которое Вы запустили на своём компьютере, каждая программа, каждое "окно" запускает какой-то процесс. И обычно на включенном компьютере **одновременно** запущено множество процессов.
+* И **одна программа** может запустить **несколько параллельных процессов**.
+
+Если Вы заглянете в "диспетчер задач" или "системный монитор" (или аналогичные инструменты) Вашей операционной системы, то увидите множество работающих процессов.
+
+Вполне вероятно, что Вы увидите несколько процессов с одним и тем же названием браузерной программы (Firefox, Chrome, Edge и т. Д.). Обычно браузеры запускают один процесс на вкладку и вдобавок некоторые дополнительные процессы.
+
+
+
+---
+
+Теперь, когда нам известна разница между **процессом** и **программой**, давайте продолжим обсуждение развёртывания.
+
+## Настройки запуска приложения
+
+В большинстве случаев когда Вы создаёте веб-приложение, то желаете, чтоб оно **работало постоянно** и непрерывно, предоставляя клиентам доступ в любое время. Хотя иногда у Вас могут быть причины, чтоб оно запускалось только при определённых условиях.
+
+### Удалённый сервер
+
+Когда Вы настраиваете удалённый сервер (облачный сервер, виртуальную машину и т.п.), самое простое, что можно сделать, запустить Uvicorn (или его аналог) вручную, как Вы делаете при локальной разработке.
+
+Это рабочий способ и он полезен **во время разработки**.
+
+Но если Вы потеряете соединение с сервером, то не сможете отслеживать - работает ли всё ещё **запущенный Вами процесс**.
+
+И если сервер перезагрузится (например, после обновления или каких-то действий облачного провайдера), Вы скорее всего **этого не заметите**, чтобы снова запустить процесс вручную. Вследствие этого Ваш API останется мёртвым. 😱
+
+### Автоматический запуск программ
+
+Вероятно Вы пожелаете, чтоб Ваша серверная программа (такая как Uvicorn) стартовала автоматически при включении сервера, без **человеческого вмешательства** и всегда могла управлять Вашим API (так как Uvicorn запускает приложение FastAPI).
+
+### Отдельная программа
+
+Для этого у обычно используют отдельную программу, которая следит за тем, чтобы Ваши приложения запускались при включении сервера. Такой подход гарантирует, что другие компоненты или приложения также будут запущены, например, база данных
+
+### Примеры инструментов, управляющих запуском программ
+
+Вот несколько примеров, которые могут справиться с такой задачей:
+
+* Docker
+* Kubernetes
+* Docker Compose
+* Docker в режиме Swarm
+* Systemd
+* Supervisor
+* Использование услуг облачного провайдера
+* Прочие...
+
+Я покажу Вам некоторые примеры их использования в следующих главах.
+
+## Перезапуск
+
+Вы, вероятно, также пожелаете, чтоб Ваше приложение **перезапускалось**, если в нём произошёл сбой.
+
+### Мы ошибаемся
+
+Все люди совершают **ошибки**. Программное обеспечение почти *всегда* содержит **баги** спрятавшиеся в разных местах. 🐛
+
+И мы, будучи разработчиками, продолжаем улучшать код, когда обнаруживаем в нём баги или добавляем новый функционал (возможно, добавляя при этом баги 😅).
+
+### Небольшие ошибки обрабатываются автоматически
+
+Когда Вы создаёте свои API на основе FastAPI и допускаете в коде ошибку, то FastAPI обычно остановит её распространение внутри одного запроса, при обработке которого она возникла. 🛡
+
+Клиент получит ошибку **500 Internal Server Error** в ответ на свой запрос, но приложение не сломается и будет продолжать работать с последующими запросами.
+
+### Большие ошибки - Падение приложений
+
+Тем не менее, может случиться так, что ошибка вызовет **сбой всего приложения** или даже сбой в Uvicorn, а то и в самом Python. 💥
+
+Но мы всё ещё хотим, чтобы приложение **продолжало работать** несмотря на эту единственную ошибку, обрабатывая, как минимум, запросы к *операциям пути* не имеющим ошибок.
+
+### Перезапуск после падения
+
+Для случаев, когда ошибки приводят к сбою в запущенном **процессе**, Вам понадобится добавить компонент, который **перезапустит** процесс хотя бы пару раз...
+
+!!! tip "Заметка"
+ ... Если приложение падает сразу же после запуска, вероятно бесполезно его бесконечно перезапускать. Но полагаю, Вы заметите такое поведение во время разработки или, по крайней мере, сразу после развёртывания.
+
+ Так что давайте сосредоточимся на конкретных случаях, когда приложение может полностью выйти из строя, но всё ещё есть смысл его запустить заново.
+
+Возможно Вы захотите, чтоб был некий **внешний компонент**, ответственный за перезапуск Вашего приложения даже если уже не работает Uvicorn или Python. То есть ничего из того, что написано в Вашем коде внутри приложения, не может быть выполнено в принципе.
+
+### Примеры инструментов для автоматического перезапуска
+
+В большинстве случаев инструменты **запускающие программы при старте сервера** умеют **перезапускать** эти программы.
+
+В качестве примера можно взять те же:
+
+* Docker
+* Kubernetes
+* Docker Compose
+* Docker в режиме Swarm
+* Systemd
+* Supervisor
+* Использование услуг облачного провайдера
+* Прочие...
+
+## Запуск нескольких экземпляров приложения (Репликация) - Процессы и память
+
+Приложение FastAPI, управляемое серверной программой (такой как Uvicorn), запускается как **один процесс** и может обслуживать множество клиентов одновременно.
+
+Но часто Вам может понадобиться несколько одновременно работающих одинаковых процессов.
+
+### Множество процессов - Воркеры (Workers)
+
+Если количество Ваших клиентов больше, чем может обслужить один процесс (допустим, что виртуальная машина не слишком мощная), но при этом Вам доступно **несколько ядер процессора**, то Вы можете запустить **несколько процессов** одного и того же приложения параллельно и распределить запросы между этими процессами.
+
+**Несколько запущенных процессов** одной и той же API-программы часто называют **воркерами**.
+
+### Процессы и порты́
+
+Помните ли Вы, как на странице [Об HTTPS](./https.md){.internal-link target=_blank} мы обсуждали, что на сервере только один процесс может слушать одну комбинацию IP-адреса и порта?
+
+С тех пор ничего не изменилось.
+
+Соответственно, чтобы иметь возможность работать с **несколькими процессами** одновременно, должен быть **один процесс, прослушивающий порт** и затем каким-либо образом передающий данные каждому рабочему процессу.
+
+### У каждого процесса своя память
+
+Работающая программа загружает в память данные, необходимые для её работы, например, переменные содержащие модели машинного обучения или большие файлы. Каждая переменная **потребляет некоторое количество оперативной памяти (RAM)** сервера.
+
+Обычно процессы **не делятся памятью друг с другом**. Сие означает, что каждый работающий процесс имеет свои данные, переменные и свой кусок памяти. И если для выполнения Вашего кода процессу нужно много памяти, то **каждый такой же процесс** запущенный дополнительно, потребует такого же количества памяти.
+
+### Память сервера
+
+Допустим, что Ваш код загружает модель машинного обучения **размером 1 ГБ**. Когда Вы запустите своё API как один процесс, он займёт в оперативной памяти не менее 1 ГБ. А если Вы запустите **4 таких же процесса** (4 воркера), то каждый из них займёт 1 ГБ оперативной памяти. В результате Вашему API потребуется **4 ГБ оперативной памяти (RAM)**.
+
+И если Ваш удалённый сервер или виртуальная машина располагает только 3 ГБ памяти, то попытка загрузить в неё 4 ГБ данных вызовет проблемы. 🚨
+
+### Множество процессов - Пример
+
+В этом примере **менеджер процессов** запустит и будет управлять двумя **воркерами**.
+
+Менеджер процессов будет слушать определённый **сокет** (IP:порт) и передавать данные работающим процессам.
+
+Каждый из этих процессов будет запускать Ваше приложение для обработки полученного **запроса** и возвращения вычисленного **ответа** и они будут использовать оперативную память.
+
+
+
+Безусловно, на этом же сервере будут работать и **другие процессы**, которые не относятся к Вашему приложению.
+
+Интересная деталь - обычно в течение времени процент **использования центрального процессора (CPU)** каждым процессом может очень сильно **изменяться**, но объём занимаемой **оперативной памяти (RAM)** остаётся относительно **стабильным**.
+
+Если у Вас есть API, который каждый раз выполняет сопоставимый объем вычислений, и у Вас много клиентов, то **загрузка процессора**, вероятно, *также будет стабильной* (вместо того, чтобы постоянно быстро увеличиваться и уменьшаться).
+
+### Примеры стратегий и инструментов для запуска нескольких экземпляров приложения
+
+Существует несколько подходов для достижения целей репликации и я расскажу Вам больше о конкретных стратегиях в следующих главах, например, когда речь пойдет о Docker и контейнерах.
+
+Основное ограничение при этом - только **один** компонент может работать с определённым **портом публичного IP**. И должен быть способ **передачи** данных между этим компонентом и копиями **процессов/воркеров**.
+
+Вот некоторые возможные комбинации и стратегии:
+
+* **Gunicorn** управляющий **воркерами Uvicorn**
+ * Gunicorn будет выступать как **менеджер процессов**, прослушивая **IP:port**. Необходимое количество запущенных экземпляров приложения будет осуществляться посредством запуска **множества работающих процессов Uvicorn**.
+* **Uvicorn** управляющий **воркерами Uvicorn**
+ * Один процесс Uvicorn будет выступать как **менеджер процессов**, прослушивая **IP:port**. Он будет запускать **множество работающих процессов Uvicorn**.
+* **Kubernetes** и аналогичные **контейнерные системы**
+ * Какой-то компонент в **Kubernetes** будет слушать **IP:port**. Необходимое количество запущенных экземпляров приложения будет осуществляться посредством запуска **нескольких контейнеров**, в каждом из которых работает **один процесс Uvicorn**.
+* **Облачные сервисы**, которые позаботятся обо всём за Вас
+ * Возможно, что облачный сервис умеет **управлять запуском дополнительных экземпляров приложения**. Вероятно, он потребует, чтоб Вы указали - какой **процесс** или **образ** следует клонировать. Скорее всего, Вы укажете **один процесс Uvicorn** и облачный сервис будет запускать его копии при необходимости.
+
+!!! tip "Заметка"
+ Если Вы не знаете, что такое **контейнеры**, Docker или Kubernetes, не переживайте.
+
+ Я поведаю Вам о контейнерах, образах, Docker, Kubernetes и т.п. в главе: [FastAPI внутри контейнеров - Docker](./docker.md){.internal-link target=_blank}.
+
+## Шаги, предшествующие запуску
+
+Часто бывает, что Вам необходимо произвести какие-то подготовительные шаги **перед запуском** своего приложения.
+
+Например, запустить **миграции базы данных**.
+
+Но в большинстве случаев такие действия достаточно произвести **однократно**.
+
+Поэтому Вам нужен будет **один процесс**, выполняющий эти **подготовительные шаги** до запуска приложения.
+
+Также Вам нужно будет убедиться, что этот процесс выполнил подготовительные шаги *даже* если впоследствии Вы запустите **несколько процессов** (несколько воркеров) самого приложения. Если бы эти шаги выполнялись в каждом **клонированном процессе**, они бы **дублировали** работу, пытаясь выполнить её **параллельно**. И если бы эта работа была бы чем-то деликатным, вроде миграции базы данных, то это может вызвать конфликты между ними.
+
+Безусловно, возможны случаи, когда нет проблем при выполнении предварительной подготовки параллельно или несколько раз. Тогда Вам повезло, работать с ними намного проще.
+
+!!! tip "Заметка"
+ Имейте в виду, что в некоторых случаях запуск Вашего приложения **может не требовать каких-либо предварительных шагов вовсе**.
+
+ Что ж, тогда Вам не нужно беспокоиться об этом. 🤷
+
+### Примеры стратегий запуска предварительных шагов
+
+Существует **сильная зависимость** от того, как Вы **развёртываете свою систему**, запускаете программы, обрабатываете перезапуски и т.д.
+
+Вот некоторые возможные идеи:
+
+* При использовании Kubernetes нужно предусмотреть "инициализирующий контейнер", запускаемый до контейнера с приложением.
+* Bash-скрипт, выполняющий предварительные шаги, а затем запускающий приложение.
+ * При этом Вам всё ещё нужно найти способ - как запускать/перезапускать *такой* bash-скрипт, обнаруживать ошибки и т.п.
+
+!!! tip "Заметка"
+ Я приведу Вам больше конкретных примеров работы с контейнерами в главе: [FastAPI внутри контейнеров - Docker](./docker.md){.internal-link target=_blank}.
+
+## Утилизация ресурсов
+
+Ваш сервер располагает ресурсами, которые Ваши программы могут потреблять или **утилизировать**, а именно - время работы центрального процессора и объём оперативной памяти.
+
+Как много системных ресурсов Вы предполагаете потребить/утилизировать? Если не задумываться, то можно ответить - "немного", но на самом деле Вы, вероятно, пожелаете использовать **максимально возможное количество**.
+
+Если Вы платите за содержание трёх серверов, но используете лишь малую часть системных ресурсов каждого из них, то Вы **выбрасываете деньги на ветер**, а также **впустую тратите электроэнергию** и т.п.
+
+В таком случае было бы лучше обойтись двумя серверами, но более полно утилизировать их ресурсы (центральный процессор, оперативную память, жёсткий диск, сети передачи данных и т.д).
+
+С другой стороны, если Вы располагаете только двумя серверами и используете **на 100% их процессоры и память**, но какой-либо процесс запросит дополнительную память, то операционная система сервера будет использовать жёсткий диск для расширения оперативной памяти (а диск работает в тысячи раз медленнее), а то вовсе **упадёт**. Или если какому-то процессу понадобится произвести вычисления, то ему придётся подождать, пока процессор освободится.
+
+В такой ситуации лучше подключить **ещё один сервер** и перераспределить процессы между серверами, чтоб всем **хватало памяти и процессорного времени**.
+
+Также есть вероятность, что по какой-то причине возник **всплеск** запросов к Вашему API. Возможно, это был вирус, боты или другие сервисы начали пользоваться им. И для таких происшествий Вы можете захотеть иметь дополнительные ресурсы.
+
+При настройке логики развёртываний, Вы можете указать **целевое значение** утилизации ресурсов, допустим, **от 50% до 90%**. Обычно эти метрики и используют.
+
+Вы можете использовать простые инструменты, такие как `htop`, для отслеживания загрузки центрального процессора и оперативной памяти сервера, в том числе каждым процессом. Или более сложные системы мониторинга нескольких серверов.
+
+## Резюме
+
+Вы прочитали некоторые из основных концепций, которые необходимо иметь в виду при принятии решения о развертывании приложений:
+
+* Использование более безопасного протокола HTTPS
+* Настройки запуска приложения
+* Перезагрузка приложения
+* Запуск нескольких экземпляров приложения
+* Управление памятью
+* Использование перечисленных функций перед запуском приложения.
+
+Осознание этих идей и того, как их применять, должно дать Вам интуитивное понимание, необходимое для принятия решений при настройке развертываний. 🤓
+
+В следующих разделах я приведу более конкретные примеры возможных стратегий, которым Вы можете следовать. 🚀
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:
+
+* Протокол HTTPS предполагает, что **серверу** нужно **располагать "сертификатами"** сгенерированными **третьей стороной**.
+ * На самом деле эти сертификаты **приобретены** у третьей стороны, а не "сгенерированы".
+* У сертификатов есть **срок годности**.
+ * Срок годности **истекает**.
+ * По истечении срока годности их нужно **обновить**, то есть **снова получить** у третьей стороны.
+* Шифрование соединения происходит **на уровне протокола TCP**.
+ * Протокол TCP находится на один уровень **ниже протокола HTTP**.
+ * Поэтому **проверка сертификатов и шифрование** происходит **до HTTP**.
+* **TCP не знает о "доменах"**, но знает об IP-адресах.
+ * Информация о **запрашиваемом домене** извлекается из запроса **на уровне HTTP**.
+* **Сертификаты HTTPS** "сертифицируют" **конкретный домен**, но проверка сертификатов и шифрование данных происходит на уровне протокола TCP, то есть **до того**, как станет известен домен-получатель данных.
+* **По умолчанию** это означает, что у Вас может быть **только один сертификат HTTPS на один IP-адрес**.
+ * Не важно, насколько большой у Вас сервер и насколько маленькие приложения на нём могут быть.
+ * Однако, у этой проблемы есть **решение**.
+* Существует **расширение** протокола **TLS** (который работает на уровне TCP, то есть до HTTP) называемое **
**.
+ * Расширение SNI позволяет одному серверу (с **одним IP-адресом**) иметь **несколько сертификатов HTTPS** и обслуживать **множество HTTPS-доменов/приложений**.
+ * Чтобы эта конструкция работала, **один** её компонент (программа) запущенный на сервере и слушающий **публичный IP-адрес**, должен иметь **все сертификаты HTTPS** для этого сервера.
+* **После** установления защищённого соединения, протоколом передачи данных **остаётся HTTP**.
+ * Но данные теперь **зашифрованы**, несмотря на то, что они передаются по **протоколу HTTP**.
+
+Обычной практикой является иметь **одну программу/HTTP-сервер** запущенную на сервере (машине, хосте и т.д.) и **ответственную за всю работу с HTTPS**:
+
+* получение **зашифрованных HTTPS-запросов**
+* отправка **расшифрованных HTTP запросов** в соответствующее HTTP-приложение, работающее на том же сервере (в нашем случае, это приложение **FastAPI**)
+* получние **HTTP-ответа** от приложения
+* **шифрование ответа** используя подходящий **сертификат HTTPS**
+* отправка зашифрованного **HTTPS-ответа клиенту**.
+Такой сервер часто называют **
** или просто "прокси-сервер".
+
+Вот некоторые варианты, которые Вы можете использовать в качестве такого прокси-сервера:
+
+* Traefik (может обновлять сертификаты)
+* Caddy (может обновлять сертификаты)
+* Nginx
+* HAProxy
+
+## Let's Encrypt (центр сертификации)
+
+До появления Let's Encrypt **сертификаты HTTPS** приходилось покупать у третьих сторон.
+
+Процесс получения такого сертификата был трудоёмким, требовал предоставления подтверждающих документов и сертификаты стоили дорого.
+
+Но затем консорциумом Linux Foundation был создан проект **
**.
+
+Он автоматически предоставляет **бесплатные сертификаты 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**.
+
+Существует три наиболее распространённые альтернативы:
+
+*
: ASGI сервер, созданный для Django Channels.
+
+## Сервер как машина и сервер как программа
+
+В этих терминах есть некоторые различия и Вам следует запомнить их. 💡
+
+Слово "**сервер**" чаще всего используется в двух контекстах:
+
+- удалённый или расположенный в "облаке" компьютер (физическая или виртуальная машина).
+- программа, запущенная на таком компьютере (например, Uvicorn).
+
+Просто запомните, если Вам встретился термин "сервер", то обычно он подразумевает что-то из этих двух смыслов.
+
+Когда имеют в виду именно удалённый компьютер, часто говорят просто **сервер**, но ещё его называют **машина**, **ВМ** (виртуальная машина), **нода**. Все эти термины обозначают одно и то же - удалённый компьютер, обычно под управлением Linux, на котором Вы запускаете программы.
+
+## Установка программного сервера
+
+Вы можете установить сервер, совместимый с протоколом ASGI, так:
+
+=== "Uvicorn"
+
+ *
+
+ ```console
+ $ pip install "uvicorn[standard]"
+
+ ---> 100%
+ ```
+
+
+
+ !!! tip "Подсказка"
+ С опцией `standard`, Uvicorn будет установливаться и использоваться с некоторыми дополнительными рекомендованными зависимостями.
+
+ В них входит `uvloop`, высокопроизводительная замена `asyncio`, которая значительно ускоряет работу асинхронных программ.
+
+=== "Hypercorn"
+
+ *
+
+ ```console
+ $ pip install hypercorn
+
+ ---> 100%
+ ```
+
+
+
+ ...или какой-либо другой ASGI сервер.
+
+## Запуск серверной программы
+
+Затем запустите Ваше приложение так же, как было указано в руководстве ранее, но без опции `--reload`:
+
+=== "Uvicorn"
+
+
+
+ ```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** основаны на
.
+
+
+Тем не менее Uvicorn совместим только с asyncio и обычно используется совместно с
, высокопроизводительной заменой `asyncio`.
+
+Но если Вы хотите использовать **Trio** напрямую, то можете воспользоваться **Hypercorn**, так как они совместимы. ✨
+
+### Установка Hypercorn с Trio
+
+Для начала, Вам нужно установить Hypercorn с поддержкой Trio:
+
+
+
+### Запуск с Trio
+
+Далее запустите Hypercorn с опцией `--worker-class` и аргументом `trio`:
+
+
+
+Hypercorn, в свою очередь, запустит Ваше приложение использующее Trio.
+
+Таким образом, Вы сможете использовать Trio в своём приложении. Но лучше использовать AnyIO, для сохранения совместимости и с Trio, и с asyncio. 🎉
+
+## Концепции развёртывания
+
+В вышеприведённых примерах серверные программы (например Uvicorn) запускали только **один процесс**, принимающий входящие запросы с любого IP (на это указывал аргумент `0.0.0.0`) на определённый порт (в примерах мы указывали порт `80`).
+
+Это основная идея. Но возможно, Вы озаботитесь добавлением дополнительных возможностей, таких как:
+
+* Использование более безопасного протокола HTTPS
+* Настройки запуска приложения
+* Перезагрузка приложения
+* Запуск нескольких экземпляров приложения
+* Управление памятью
+* Использование перечисленных функций перед запуском приложения.
+
+Я поведаю Вам больше о каждой из этих концепций в следующих главах, с конкретными примерами стратегий работы с ними. 🚀
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**. 🐦
+
+## Добавить **FastAPI** звезду на GitHub
+
+Вы можете добавить FastAPI "звезду" на GitHub (кликнуть на кнопку звезды в верхнем правом углу экрана):
. ⭐️
+
+Чем больше звёзд, тем легче другим пользователям найти нас и увидеть, что проект уже стал полезным для многих.
+
+## Отслеживать свежие выпуски в репозитории на GitHub
+
+Вы можете "отслеживать" FastAPI на GitHub (кликните по кнопке "watch" наверху справа):
. 👀
+
+Там же Вы можете указать в настройках - "Releases only".
+
+С такой настройкой Вы будете получать уведомления на вашу электронную почту каждый раз, когда появится новый релиз (новая версия) **FastAPI** с исправлениями ошибок и новыми возможностями.
+
+## Связаться с автором
+
+Можно связаться со
.
+ * Посмотреть другие мои проекты с открытым кодом, которые могут быть полезны Вам.
+ * Подписавшись на меня Вы сможете получать уведомления, что я создал новый проект с открытым кодом,.
+*
.
+ * Поделиться со мной, как Вы используете FastAPI (я обожаю читать про это).
+ * Получать уведомления, когда я делаю объявления и представляю новые инструменты.
+ * Вы также можете
.
+ * Получать уведомления, когда я делаю объявления и представляю новые инструменты (правда чаще всего я использую Twitter 🤷♂).
+* Читать, что я пишу (или подписаться на меня) в
.
+ * Читать другие идеи, статьи и читать об инструментах созданных мной.
+ * Подпишитесь на меня, чтобы прочитать, когда я опубликую что-нибудь новое.
+
+## Оставить сообщение в Twitter о **FastAPI**
+
+
и позвольте мне и другим узнать - почему он Вам нравится. 🎉
+
+Я люблю узнавать о том, как **FastAPI** используется, что Вам понравилось в нём, в каких проектах/компаниях Вы используете его и т.п.
+
+## Оставить голос за FastAPI
+
+*
испытывают другие люди и попытаться помочь им. Чаще всего это вопросы, на которые, весьма вероятно, Вы уже знаете ответ. 🤓
+
+Если Вы будете много помогать людям с решением их проблем, Вы можете стать официальным [Экспертом FastAPI](fastapi-people.md#experts){.internal-link target=_blank}. 🎉
+
+Только помните, самое важное при этом - доброта. Столкнувшись с проблемой, люди расстраиваются и часто задают вопросы не лучшим образом, но постарайтесь быть максимально доброжелательным. 🤗
+
+Идея сообщества **FastAPI** в том, чтобы быть добродушным и гостеприимными. Не допускайте издевательств или неуважительного поведения по отношению к другим. Мы должны заботиться друг о друге.
+
+---
+
+Как помочь другим с их проблемами:
+
+### Понять вопрос
+
+* Удостоверьтесь, что поняли **цель** и обстоятельства случая вопрошающего.
+
+* Затем проверьте, что вопрос (в подавляющем большинстве - это вопросы) Вам **ясен**.
+
+* Во многих случаях вопрос касается решения, которое пользователь придумал сам, но может быть и решение **получше**. Если Вы поймёте проблему и обстоятельства случая, то сможете предложить **альтернативное решение**.
+
+* Ежели вопрос Вам непонятен, запросите больше **деталей**.
+
+### Воспроизвести проблему
+
+В большинстве случаев есть что-то связанное с **исходным кодом** вопрошающего.
+
+И во многих случаях будет предоставлен только фрагмент этого кода, которого недостаточно для **воспроизведения проблемы**.
+
+* Попросите предоставить
, который можно **скопировать** и запустить локально дабы увидеть такую же ошибку, или поведение, или лучше понять обстоятельства случая.
+
+* Если на Вас нахлынуло великодушие, то можете попытаться **создать похожий пример** самостоятельно, основываясь только на описании проблемы. Но имейте в виду, что это может занять много времени и, возможно, стоит сначала позадавать вопросы для прояснения проблемы.
+
+### Предложить решение
+
+* После того как Вы поняли вопрос, Вы можете дать **ответ**.
+
+* Следует понять **основную проблему и обстоятельства случая**, потому что может быть решение лучше, чем то, которое пытались реализовать.
+
+### Попросить закрыть проблему
+
+Если Вам ответили, высоки шансы, что Вам удалось решить проблему, поздравляю, **Вы - герой**! 🦸
+
+* В таком случае, если вопрос решён, попросите **закрыть проблему**.
+
+## Отслеживать репозиторий на GitHub
+
+Вы можете "отслеживать" FastAPI на GitHub (кликните по кнопке "watch" наверху справа):
. 👀
+
+Если Вы выберете "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** и следить за тем, чтобы он продолжал **развиваться быстрее и лучше**. 🚀
+
+## Подключиться к чату
+
+Подключайтесь к 👥
👥 и общайтесь с другими участниками сообщества FastAPI.
+
+!!! Подсказка
+ Вопросы по проблемам с фреймворком лучше задавать в
, так больше шансов, что Вы получите помощь от [Экспертов FastAPI](fastapi-people.md#experts){.internal-link target=_blank}.
+
+ Используйте этот чат только для бесед на отвлечённые темы.
+
+Существует также
, но поскольку в нем нет каналов и расширенных функций, общение в нём сложнее, потому рекомендуемой системой является Discord.
+
+### Не использовать чаты для вопросов
+
+Имейте в виду, что чаты позволяют больше "свободного общения", потому там легко задавать вопросы, которые слишком общие и на которые труднее ответить, так что Вы можете не получить нужные Вам ответы.
+
+В разделе "проблемы" на GitHub, есть шаблон, который поможет Вам написать вопрос правильно, чтобы Вам было легче получить хороший ответ или даже решить проблему самостоятельно, прежде чем Вы зададите вопрос. В GitHub я могу быть уверен, что всегда отвечаю на всё, даже если это займет какое-то время. И я не могу сделать то же самое в чатах. 😅
+
+Кроме того, общение в чатах не так легкодоступно для поиска, как в GitHub, потому вопросы и ответы могут потеряться среди другого общения. И только проблемы решаемые на GitHub учитываются в получении лычки [Эксперт FastAPI](fastapi-people.md#experts){.internal-link target=_blank}, так что весьма вероятно, что Вы получите больше внимания на GitHub.
+
+С другой стороны, в чатах тысячи пользователей, а значит есть большие шансы в любое время найти там кого-то, с кем можно поговорить. 😄
+
+## Спонсировать автора
+
+Вы также можете оказать мне финансовую поддержку посредством
.
+
+Там можно просто купить мне кофе ☕️ в знак благодарности. 😄
+
+А ещё Вы можете стать Серебряным или Золотым спонсором для FastAPI. 🏅🎉
+
+## Спонсировать инструменты, на которых зиждется мощь FastAPI
+
+Как Вы могли заметить в документации, FastAPI опирается на плечи титанов: Starlette и Pydantic.
+
+Им тоже можно оказать спонсорскую поддержку:
+
+*
+
+---
+
+Благодарствую! 🚀
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 @@
+# История создания и дальнейшее развитие
+
+Однажды,
:
+
+> Какова история этого проекта? Создаётся впечатление, что он явился из ниоткуда и завоевал мир за несколько недель [...]
+
+Что ж, вот небольшая часть истории проекта.
+
+## Альтернативы
+
+В течение нескольких лет я, возглавляя различные команды разработчиков, создавал довольно сложные API для машинного обучения, распределённых систем, асинхронных задач, баз данных NoSQL и т.д.
+
+В рамках работы над этими проектами я исследовал, проверял и использовал многие фреймворки.
+
+Во многом история **FastAPI** - история его предшественников.
+
+Как написано в разделе [Альтернативы](alternatives.md){.internal-link target=_blank}:
+
+
+
+## Исследования
+
+Благодаря опыту использования существующих альтернатив, мы с коллегами изучили их основные идеи и скомбинировали собранные знания наилучшим образом.
+
+Например, стало ясно, что необходимо брать за основу стандартные подсказки типов Python, а самым лучшим подходом является использование уже существующих стандартов.
+
+Итак, прежде чем приступить к написанию **FastAPI**, я потратил несколько месяцев на изучение OpenAPI, JSON Schema, OAuth2, и т.п. для понимания их взаимосвязей, совпадений и различий.
+
+## Дизайн
+
+Затем я потратил некоторое время на придумывание "API" разработчика, который я хотел иметь как пользователь (как разработчик, использующий FastAPI).
+
+Я проверил несколько идей на самых популярных редакторах кода среди Python-разработчиков: PyCharm, VS Code, Jedi.
+
+Данные по редакторам я взял из
, который охватываает около 80% пользователей.
+
+Это означает, что **FastAPI** был специально проверен на редакторах, используемых 80% Python-разработчиками. И поскольку большинство других редакторов, как правило, работают аналогичным образом, все его преимущества должны работать практически для всех редакторов.
+
+Таким образом, я смог найти наилучшие способы сократить дублирование кода, обеспечить повсеместное автодополнение, проверку типов и ошибок и т.д.
+
+И все это, чтобы все пользователи могли получать наилучший опыт разработки.
+
+## Зависимости
+
+Протестировав несколько вариантов, я решил, что в качестве основы буду использовать
и его преимущества.
+
+По моим предложениям был изменён код этого фреймворка, чтобы сделать его полностью совместимым с JSON Schema, поддержать различные способы определения ограничений и улучшить помощь редакторов (проверки типов, автозаполнение).
+
+В то же время, я принимал участие в разработке
, ещё один из основных компонентов 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:
+
+### Full Stack FastAPI PostgreSQL - Особенности
+
+* Полностью интегрирован с **Docker** (основан на Docker).
+* Развёртывается в режиме Docker Swarm.
+* Интегрирован с **Docker Compose** и оптимизирован для локальной разработки.
+* **Готовый к реальной работе** веб-сервер Python использующий Uvicorn и Gunicorn.
+* Бэкенд построен на фреймворке
:
+ * **Быстрый**: Высокопроизводительный, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic).
+ * **Интуитивно понятный**: Отличная поддержка редактора.
везде. Меньше времени на отладку.
+ * **Простой**: Разработан так, чтоб быть простым в использовании и изучении. Меньше времени на чтение документации.
+ * **Лаконичный**: Минимизировано повторение кода. Каждый объявленный параметр определяет несколько функций.
+ * **Надёжный**: Получите готовый к работе код. С автоматической интерактивной документацией.
+ * **Стандартизированный**: Основан на открытых стандартах API (
включая автоматическую проверку и сериализацию данных, интерактивную документацию, аутентификацию с помощью 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:
+
+⚠️ **ПРЕДУПРЕЖДЕНИЕ** ⚠️
+
+Если Вы начинаете новый проект, ознакомьтесь с представленными здесь альтернативами.
+
+Например, генератор проектов
может быть более подходящей альтернативой, так как он активно поддерживается и используется. И он включает в себя все новые возможности и улучшения.
+
+Но никто не запрещает Вам использовать генератор с СУБД Couchbase, возможно, он всё ещё работает нормально. Или у Вас уже есть проект, созданный с помощью этого генератора ранее, и Вы, вероятно, уже обновили его в соответствии со своими потребностями.
+
+Вы можете прочитать о нём больше в документации соответствующего репозитория.
+
+## Full Stack FastAPI MongoDB
+
+...может быть когда-нибудь появится, в зависимости от наличия у меня свободного времени и прочих факторов. 😅 🎉
+
+## Модели машинного обучения на основе spaCy и FastAPI
+
+GitHub:
+
+### Модели машинного обучения на основе 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/body-multiple-params.md b/docs/ru/docs/tutorial/body-multiple-params.md
new file mode 100644
index 000000000..a20457092
--- /dev/null
+++ b/docs/ru/docs/tutorial/body-multiple-params.md
@@ -0,0 +1,309 @@
+# Body - Множество параметров
+
+Теперь, когда мы увидели, как использовать `Path` и `Query` параметры, давайте рассмотрим более продвинутые примеры обьявления тела запроса.
+
+## Обьединение `Path`, `Query` и параметров тела запроса
+
+Во-первых, конечно, вы можете объединять параметры `Path`, `Query` и объявления тела запроса в своих функциях обработки, **FastAPI** автоматически определит, что с ними нужно делать.
+
+Вы также можете объявить параметры тела запроса как необязательные, установив значение по умолчанию, равное `None`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="18-20"
+ {!> ../../../docs_src/body_multiple_params/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="18-20"
+ {!> ../../../docs_src/body_multiple_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="19-21"
+ {!> ../../../docs_src/body_multiple_params/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! Заметка
+ Рекомендуется использовать `Annotated` версию, если это возможно.
+
+ ```Python hl_lines="17-19"
+ {!> ../../../docs_src/body_multiple_params/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! Заметка
+ Рекомендуется использовать версию с `Annotated`, если это возможно.
+
+ ```Python hl_lines="19-21"
+ {!> ../../../docs_src/body_multiple_params/tutorial001.py!}
+ ```
+
+!!! Заметка
+ Заметьте, что в данном случае параметр `item`, который будет взят из тела запроса, необязателен. Так как было установлено значение `None` по умолчанию.
+
+## Несколько параметров тела запроса
+
+В предыдущем примере, *операции пути* ожидали тело запроса в формате JSON-тело с параметрами, соответствующими атрибутам `Item`, например:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+}
+```
+
+Но вы также можете объявить множество параметров тела запроса, например `item` и `user`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/body_multiple_params/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="22"
+ {!> ../../../docs_src/body_multiple_params/tutorial002.py!}
+ ```
+
+В этом случае **FastAPI** заметит, что в функции есть более одного параметра тела (два параметра, которые являются моделями Pydantic).
+
+Таким образом, имена параметров будут использоваться в качестве ключей (имён полей) в теле запроса, и будет ожидаться запрос следующего формата:
+
+```JSON
+{
+ "item": {
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+ },
+ "user": {
+ "username": "dave",
+ "full_name": "Dave Grohl"
+ }
+}
+```
+
+!!! Внимание
+ Обратите внимание, что хотя параметр `item` был объявлен таким же способом, как и раньше, теперь предпологается, что он находится внутри тела с ключом `item`.
+
+
+**FastAPI** сделает автоматические преобразование из запроса, так что параметр `item` получит своё конкретное содержимое, и то же самое происходит с пользователем `user`.
+
+Произойдёт проверка составных данных, и создание документации в схеме OpenAPI и автоматических документах.
+
+## Отдельные значения в теле запроса
+
+Точно так же, как `Query` и `Path` используются для определения дополнительных данных для query и path параметров, **FastAPI** предоставляет аналогичный инструмент - `Body`.
+
+Например, расширяя предыдущую модель, вы можете решить, что вам нужен еще один ключ `importance` в том же теле запроса, помимо параметров `item` и `user`.
+
+Если вы объявите его без указания, какой именно объект (Path, Query, Body и .т.п.) ожидаете, то, поскольку это является простым типом данных, **FastAPI** будет считать, что это query-параметр.
+
+Но вы можете указать **FastAPI** обрабатывать его, как ещё один ключ тела запроса, используя `Body`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="23"
+ {!> ../../../docs_src/body_multiple_params/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="23"
+ {!> ../../../docs_src/body_multiple_params/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="24"
+ {!> ../../../docs_src/body_multiple_params/tutorial003_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! Заметка
+ Рекомендуется использовать `Annotated` версию, если это возможно.
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/body_multiple_params/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! Заметка
+ Рекомендуется использовать `Annotated` версию, если это возможно.
+
+ ```Python hl_lines="22"
+ {!> ../../../docs_src/body_multiple_params/tutorial003.py!}
+ ```
+
+В этом случае, **FastAPI** будет ожидать тело запроса в формате:
+
+```JSON
+{
+ "item": {
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+ },
+ "user": {
+ "username": "dave",
+ "full_name": "Dave Grohl"
+ },
+ "importance": 5
+}
+```
+
+И всё будет работать так же - преобразование типов данных, валидация, документирование и т.д.
+
+## Множество body и query параметров
+
+Конечно, вы также можете объявлять query-параметры в любое время, дополнительно к любым body-параметрам.
+
+Поскольку по умолчанию, отдельные значения интерпретируются как query-параметры, вам не нужно явно добавлять `Query`, вы можете просто сделать так:
+
+```Python
+q: Union[str, None] = None
+```
+
+Или в Python 3.10 и выше:
+
+```Python
+q: str | None = None
+```
+
+Например:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="27"
+ {!> ../../../docs_src/body_multiple_params/tutorial004_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="27"
+ {!> ../../../docs_src/body_multiple_params/tutorial004_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="28"
+ {!> ../../../docs_src/body_multiple_params/tutorial004_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! Заметка
+ Рекомендуется использовать `Annotated` версию, если это возможно.
+
+ ```Python hl_lines="25"
+ {!> ../../../docs_src/body_multiple_params/tutorial004_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! Заметка
+ Рекомендуется использовать `Annotated` версию, если это возможно.
+
+ ```Python hl_lines="27"
+ {!> ../../../docs_src/body_multiple_params/tutorial004.py!}
+ ```
+
+!!! Информация
+ `Body` также имеет все те же дополнительные параметры валидации и метаданных, как у `Query`,`Path` и других, которые вы увидите позже.
+
+## Добавление одного body-параметра
+
+Предположим, у вас есть только один body-параметр `item` из Pydantic модели `Item`.
+
+По умолчанию, **FastAPI** ожидает получить тело запроса напрямую.
+
+Но если вы хотите чтобы он ожидал JSON с ключом `item` с содержимым модели внутри, также как это происходит при объявлении дополнительных body-параметров, вы можете использовать специальный параметр `embed` у типа `Body`:
+
+```Python
+item: Item = Body(embed=True)
+```
+
+так же, как в этом примере:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/body_multiple_params/tutorial005_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/body_multiple_params/tutorial005_an_py39.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/body_multiple_params/tutorial005_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! Заметка
+ Рекомендуется использовать `Annotated` версию, если это возможно.
+
+ ```Python hl_lines="15"
+ {!> ../../../docs_src/body_multiple_params/tutorial005_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! Заметка
+ Рекомендуется использовать `Annotated` версию, если это возможно.
+
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/body_multiple_params/tutorial005.py!}
+ ```
+
+В этом случае **FastAPI** будет ожидать тело запроса в формате:
+
+```JSON hl_lines="2"
+{
+ "item": {
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+ }
+}
+```
+
+вместо этого:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+}
+```
+
+## Резюме
+
+Вы можете добавлять несколько body-параметров вашей *функции операции пути*, несмотря даже на то, что запрос может содержать только одно тело.
+
+Но **FastAPI** справится с этим, предоставит правильные данные в вашей функции, а также сделает валидацию и документацию правильной схемы *операции пути*.
+
+Вы также можете объявить отдельные значения для получения в рамках тела запроса.
+
+И вы можете настроить **FastAPI** таким образом, чтобы включить тело запроса в ключ, даже если объявлен только один параметр.
diff --git a/docs/ru/docs/tutorial/body.md b/docs/ru/docs/tutorial/body.md
new file mode 100644
index 000000000..c03d40c3f
--- /dev/null
+++ b/docs/ru/docs/tutorial/body.md
@@ -0,0 +1,165 @@
+# Тело запроса
+
+Когда вам необходимо отправить данные из клиента (допустим, браузера) в ваш API, вы отправляете их как **тело запроса**.
+
+Тело **запроса** --- это данные, отправляемые клиентом в ваш API. Тело **ответа** --- это данные, которые ваш API отправляет клиенту.
+
+Ваш API почти всегда отправляет тело **ответа**. Но клиентам не обязательно всегда отправлять тело **запроса**.
+
+Чтобы объявить тело **запроса**, необходимо использовать модели
, со всей их мощью и преимуществами.
+
+!!! info "Информация"
+ Чтобы отправить данные, необходимо использовать один из методов: `POST` (обычно), `PUT`, `DELETE` или `PATCH`.
+
+ Отправка тела с запросом `GET` имеет неопределенное поведение в спецификациях, тем не менее, оно поддерживается FastAPI только для очень сложных/экстремальных случаев использования.
+
+ Поскольку это не рекомендуется, интерактивная документация со Swagger UI не будет отображать информацию для тела при использовании метода GET, а промежуточные прокси-серверы могут не поддерживать такой вариант запроса.
+
+## Импортирование `BaseModel` из Pydantic
+
+Первое, что вам необходимо сделать, это импортировать `BaseModel` из пакета `pydantic`:
+
+```Python hl_lines="4"
+{!../../../docs_src/body/tutorial001.py!}
+```
+
+## Создание вашей собственной модели
+
+После этого вы описываете вашу модель данных как класс, наследующий от `BaseModel`.
+
+Используйте аннотации типов Python для всех атрибутов:
+
+```Python hl_lines="7-11"
+{!../../../docs_src/body/tutorial001.py!}
+```
+
+Также как и при описании параметров запроса, когда атрибут модели имеет значение по умолчанию, он является необязательным. Иначе он обязателен. Используйте `None`, чтобы сделать его необязательным без использования конкретных значений по умолчанию.
+
+Например, модель выше описывает вот такой JSON "объект" (или словарь Python):
+
+```JSON
+{
+ "name": "Foo",
+ "description": "An optional description",
+ "price": 45.2,
+ "tax": 3.5
+}
+```
+
+...поскольку `description` и `tax` являются необязательными (с `None` в качестве значения по умолчанию), вот такой JSON "объект" также подходит:
+
+```JSON
+{
+ "name": "Foo",
+ "price": 45.2
+}
+```
+
+## Объявление как параметра функции
+
+Чтобы добавить параметр к вашему *обработчику*, объявите его также, как вы объявляли параметры пути или параметры запроса:
+
+```Python hl_lines="18"
+{!../../../docs_src/body/tutorial001.py!}
+```
+
+...и укажите созданную модель в качестве типа параметра, `Item`.
+
+## Результаты
+
+Всего лишь с помощью аннотации типов Python, **FastAPI**:
+
+* Читает тело запроса как JSON.
+* Приводит к соответствующим типам (если есть необходимость).
+* Проверяет корректность данных.
+ * Если данные некорректны, будет возращена читаемая и понятная ошибка, показывающая что именно и в каком месте некорректно в данных.
+* Складывает полученные данные в параметр `item`.
+ * Поскольку внутри функции вы объявили его с типом `Item`, то теперь у вас есть поддержка со стороны редактора (автодополнение и т.п.) для всех атрибутов и их типов.
+* Генерирует декларативное описание модели в виде
, так что вы можете его использовать где угодно, если это имеет значение для вашего проекта.
+* Эти схемы являются частью сгенерированной схемы OpenAPI и используются для автоматического документирования
.
+
+## Автоматическое документирование
+
+Схема JSON ваших моделей будет частью сгенерированной схемы OpenAPI и будет отображена в интерактивной документации API:
+
+
+
+Также она будет указана в документации по API внутри каждой *операции пути*, в которой используются:
+
+
+
+## Поддержка редактора
+
+В вашем редакторе внутри вашей функции у вас будут подсказки по типам и автодополнение (это не будет работать, если вы получаете словарь вместо модели Pydantic):
+
+
+
+Это не случайно, весь фреймворк построен вокруг такого дизайна.
+
+И это все тщательно протестировано еще на этапе разработки дизайна, до реализации, чтобы это работало со всеми редакторами.
+
+Для поддержки этого даже были внесены некоторые изменения в сам Pydantic.
+
+На всех предыдущих скриншотах используется
.
+
+ Он улучшает поддержку редактором моделей Pydantic в части:
+
+ * автодополнения,
+ * проверки типов,
+ * рефакторинга,
+ * поиска,
+ * инспектирования.
+
+## Использование модели
+
+Внутри функции вам доступны все атрибуты объекта модели напрямую:
+
+```Python hl_lines="21"
+{!../../../docs_src/body/tutorial002.py!}
+```
+
+## Тело запроса + параметры пути
+
+Вы можете одновременно объявлять параметры пути и тело запроса.
+
+**FastAPI** распознает, какие параметры функции соответствуют параметрам пути и должны быть **получены из пути**, а какие параметры функции, объявленные как модели Pydantic, должны быть **получены из тела запроса**.
+
+```Python hl_lines="17-18"
+{!../../../docs_src/body/tutorial003.py!}
+```
+
+## Тело запроса + параметры пути + параметры запроса
+
+Вы также можете одновременно объявить параметры для **пути**, **запроса** и **тела запроса**.
+
+**FastAPI** распознает каждый из них и возьмет данные из правильного источника.
+
+```Python hl_lines="18"
+{!../../../docs_src/body/tutorial004.py!}
+```
+
+Параметры функции распознаются следующим образом:
+
+* Если параметр также указан в **пути**, то он будет использоваться как параметр пути.
+* Если аннотация типа параметра содержит **примитивный тип** (`int`, `float`, `str`, `bool` и т.п.), он будет интерпретирован как параметр **запроса**.
+* Если аннотация типа параметра представляет собой **модель Pydantic**, он будет интерпретирован как параметр **тела запроса**.
+
+!!! note "Заметка"
+ FastAPI понимает, что значение параметра `q` не является обязательным, потому что имеет значение по умолчанию `= None`.
+
+ Аннотация `Optional` в `Optional[str]` не используется FastAPI, но помогает вашему редактору лучше понимать ваш код и обнаруживать ошибки.
+
+## Без Pydantic
+
+Если вы не хотите использовать модели Pydantic, вы все еще можете использовать параметры **тела запроса**. Читайте в документации раздел [Тело - Несколько параметров: Единичные значения в теле](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
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/debugging.md b/docs/ru/docs/tutorial/debugging.md
new file mode 100644
index 000000000..755d98cf2
--- /dev/null
+++ b/docs/ru/docs/tutorial/debugging.md
@@ -0,0 +1,112 @@
+# Отладка
+
+Вы можете подключить отладчик в своем редакторе, например, в Visual Studio Code или PyCharm.
+
+## Вызов `uvicorn`
+
+В вашем FastAPI приложении, импортируйте и вызовите `uvicorn` напрямую:
+
+```Python hl_lines="1 15"
+{!../../../docs_src/debugging/tutorial001.py!}
+```
+
+### Описание `__name__ == "__main__"`
+
+Главная цель использования `__name__ == "__main__"` в том, чтобы код выполнялся при запуске файла с помощью:
+
+
+
+но не вызывался, когда другой файл импортирует это, например::
+
+```Python
+from myapp import app
+```
+
+#### Больше деталей
+
+Давайте назовём ваш файл `myapp.py`.
+
+Если вы запустите его с помощью:
+
+
+
+то встроенная переменная `__name__`, автоматически создаваемая Python в вашем файле, будет иметь значение строкового типа `"__main__"`.
+
+Тогда выполнится условие и эта часть кода:
+
+```Python
+ uvicorn.run(app, host="0.0.0.0", port=8000)
+```
+
+будет запущена.
+
+---
+
+Но этого не произойдет, если вы импортируете этот модуль (файл).
+
+Таким образом, если у вас есть файл `importer.py` с таким импортом:
+
+```Python
+from myapp import app
+
+# Some more code
+```
+
+то автоматическая создаваемая внутри файла `myapp.py` переменная `__name__` будет иметь значение отличающееся от `"__main__"`.
+
+Следовательно, строка:
+
+```Python
+ uvicorn.run(app, host="0.0.0.0", port=8000)
+```
+
+не будет выполнена.
+
+!!! Информация
+ Для получения дополнительной информации, ознакомьтесь с
.
+
+## Запуск вашего кода с помощью отладчика
+
+Так как вы запускаете сервер Uvicorn непосредственно из вашего кода, вы можете вызвать Python программу (ваше FastAPI приложение) напрямую из отладчика.
+
+---
+
+Например, в Visual Studio Code вы можете выполнить следующие шаги:
+
+* Перейдите на панель "Debug".
+* Выберите "Add configuration...".
+* Выберите "Python"
+* Запустите отладчик "`Python: Current File (Integrated Terminal)`".
+
+Это запустит сервер с вашим **FastAPI** кодом, остановится на точках останова, и т.д.
+
+Вот как это может выглядеть:
+
+
+
+---
+
+Если используете Pycharm, вы можете выполнить следующие шаги:
+
+* Открыть "Run" меню.
+* Выбрать опцию "Debug...".
+* Затем в появившемся контекстном меню.
+* Выбрать файл для отладки (в данном случае, `main.py`).
+
+Это запустит сервер с вашим **FastAPI** кодом, остановится на точках останова, и т.д.
+
+Вот как это может выглядеть:
+
+
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 здесь:
.
+
+## Пример
+
+Вот пример *операции пути* с параметрами, который демонстрирует некоторые из вышеперечисленных типов.
+
+=== "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/first-steps.md b/docs/ru/docs/tutorial/first-steps.md
new file mode 100644
index 000000000..b46f235bc
--- /dev/null
+++ b/docs/ru/docs/tutorial/first-steps.md
@@ -0,0 +1,333 @@
+# Первые шаги
+
+Самый простой FastAPI файл может выглядеть так:
+
+```Python
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+Скопируйте в файл `main.py`.
+
+Запустите сервер в режиме реального времени:
+
+
+
+!!! note "Технические детали"
+ Команда `uvicorn main:app` обращается к:
+
+ * `main`: файл `main.py` (модуль Python).
+ * `app`: объект, созданный внутри файла `main.py` в строке `app = FastAPI()`.
+ * `--reload`: перезапускает сервер после изменения кода. Используйте только для разработки.
+
+В окне вывода появится следующая строка:
+
+```hl_lines="4"
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+Эта строка показывает URL-адрес, по которому приложение доступно на локальной машине.
+
+### Проверьте
+
+Откройте браузер по адресу:
.
+
+Вы увидите JSON-ответ следующего вида:
+
+```JSON
+{"message": "Hello World"}
+```
+
+### Интерактивная документация API
+
+Перейдите по адресу:
.
+
+Вы увидите автоматически сгенерированную, интерактивную документацию по API (предоставленную
):
+
+
+
+### Альтернативная документация API
+
+Теперь перейдите по адресу
.
+
+Вы увидите альтернативную автоматически сгенерированную документацию (предоставленную
):
+
+
+
+### OpenAPI
+
+**FastAPI** генерирует "схему" всего API, используя стандарт **OpenAPI**.
+
+#### "Схема"
+
+"Схема" - это определение или описание чего-либо. Не код, реализующий это, а только абстрактное описание.
+
+#### API "схема"
+
+
- это спецификация, которая определяет, как описывать схему API.
+
+Определение схемы содержит пути (paths) API, их параметры и т.п.
+
+#### "Схема" данных
+
+Термин "схема" также может относиться к формату или структуре некоторых данных, например, JSON.
+
+Тогда, подразумеваются атрибуты JSON, их типы данных и т.п.
+
+#### OpenAPI и JSON Schema
+
+OpenAPI описывает схему API. Эта схема содержит определения (или "схемы") данных, отправляемых и получаемых API. Для описания структуры данных в JSON используется стандарт **JSON Schema**.
+
+#### Рассмотрим `openapi.json`
+
+Если Вас интересует, как выглядит исходная схема OpenAPI, то FastAPI автоматически генерирует JSON-схему со всеми описаниями API.
+
+Можете посмотреть здесь:
.
+
+Вы увидите примерно такой JSON:
+
+```JSON
+{
+ "openapi": "3.0.2",
+ "info": {
+ "title": "FastAPI",
+ "version": "0.1.0"
+ },
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+
+
+
+...
+```
+
+#### Для чего нужен OpenAPI
+
+Схема OpenAPI является основой для обеих систем интерактивной документации.
+
+Существуют десятки альтернативных инструментов, основанных на OpenAPI. Вы можете легко добавить любой из них к **FastAPI** приложению.
+
+Вы также можете использовать OpenAPI для автоматической генерации кода для клиентов, которые взаимодействуют с API. Например, для фронтенд-, мобильных или IoT-приложений.
+
+## Рассмотрим поэтапно
+
+### Шаг 1: импортируйте `FastAPI`
+
+```Python hl_lines="1"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+`FastAPI` это класс в Python, который предоставляет всю функциональность для API.
+
+!!! note "Технические детали"
+ `FastAPI` это класс, который наследуется непосредственно от `Starlette`.
+
+ Вы можете использовать всю функциональность
в `FastAPI`.
+
+### Шаг 2: создайте экземпляр `FastAPI`
+
+```Python hl_lines="3"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+Переменная `app` является экземпляром класса `FastAPI`.
+
+Это единая точка входа для создания и взаимодействия с API.
+
+Именно к этой переменной `app` обращается `uvicorn` в команде:
+
+
+
+Если создать такое приложение:
+
+```Python hl_lines="3"
+{!../../../docs_src/first_steps/tutorial002.py!}
+```
+
+И поместить его в `main.py`, тогда вызов `uvicorn` будет таким:
+
+
+
+### Шаг 3: определите *операцию пути (path operation)*
+
+#### Путь (path)
+
+"Путь" это часть URL, после первого символа `/`, следующего за именем домена.
+
+Для URL:
+
+```
+https://example.com/items/foo
+```
+
+...путь выглядит так:
+
+```
+/items/foo
+```
+
+!!! info "Дополнительная иформация"
+ Термин "path" также часто называется "endpoint" или "route".
+
+При создании API, "путь" является основным способом разделения "задач" и "ресурсов".
+
+#### Операция (operation)
+
+"Операция" это один из "методов" HTTP.
+
+Таких, как:
+
+* `POST`
+* `GET`
+* `PUT`
+* `DELETE`
+
+...и более экзотических:
+
+* `OPTIONS`
+* `HEAD`
+* `PATCH`
+* `TRACE`
+
+По протоколу HTTP можно обращаться к каждому пути, используя один (или несколько) из этих "методов".
+
+---
+
+При создании API принято использовать конкретные HTTP-методы для выполнения определенных действий.
+
+Обычно используют:
+
+* `POST`: создать данные.
+* `GET`: прочитать.
+* `PUT`: изменить (обновить).
+* `DELETE`: удалить.
+
+В OpenAPI каждый HTTP метод называется "**операция**".
+
+Мы также будем придерживаться этого термина.
+
+#### Определите *декоратор операции пути (path operation decorator)*
+
+```Python hl_lines="6"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+Декоратор `@app.get("/")` указывает **FastAPI**, что функция, прямо под ним, отвечает за обработку запросов, поступающих по адресу:
+
+* путь `/`
+* использующих
+
+!!! info "`@decorator` Дополнительная информация"
+ Синтаксис `@something` в Python называется "декоратор".
+
+ Вы помещаете его над функцией. Как красивую декоративную шляпу (думаю, что оттуда и происходит этот термин).
+
+ "Декоратор" принимает функцию ниже и выполняет с ней какое-то действие.
+
+ В нашем случае, этот декоратор сообщает **FastAPI**, что функция ниже соответствует **пути** `/` и **операции** `get`.
+
+ Это и есть "**декоратор операции пути**".
+
+Можно также использовать операции:
+
+* `@app.post()`
+* `@app.put()`
+* `@app.delete()`
+
+И более экзотические:
+
+* `@app.options()`
+* `@app.head()`
+* `@app.patch()`
+* `@app.trace()`
+
+!!! tip "Подсказка"
+ Вы можете использовать каждую операцию (HTTP-метод) по своему усмотрению.
+
+ **FastAPI** не навязывает определенного значения для каждого метода.
+
+ Информация здесь представлена как рекомендация, а не требование.
+
+ Например, при использовании GraphQL обычно все действия выполняются только с помощью POST операций.
+
+### Шаг 4: определите **функцию операции пути**
+
+Вот "**функция операции пути**":
+
+* **путь**: `/`.
+* **операция**: `get`.
+* **функция**: функция ниже "декоратора" (ниже `@app.get("/")`).
+
+```Python hl_lines="7"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+Это обычная Python функция.
+
+**FastAPI** будет вызывать её каждый раз при получении `GET` запроса к URL "`/`".
+
+В данном случае это асинхронная функция.
+
+---
+
+Вы также можете определить ее как обычную функцию вместо `async def`:
+
+```Python hl_lines="7"
+{!../../../docs_src/first_steps/tutorial003.py!}
+```
+
+!!! note "Технические детали"
+ Если не знаете в чём разница, посмотрите [Конкурентность: *"Нет времени?"*](../async.md#in-a-hurry){.internal-link target=_blank}.
+
+### Шаг 5: верните результат
+
+```Python hl_lines="8"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+Вы можете вернуть `dict`, `list`, отдельные значения `str`, `int` и т.д.
+
+Также можно вернуть модели Pydantic (рассмотрим это позже).
+
+Многие объекты и модели будут автоматически преобразованы в JSON (включая ORM). Пробуйте использовать другие объекты, которые предпочтительней для Вас, вероятно, они уже поддерживаются.
+
+## Резюме
+
+* Импортируем `FastAPI`.
+* Создаём экземпляр `app`.
+* Пишем **декоратор операции пути** (такой как `@app.get("/")`).
+* Пишем **функцию операции пути** (`def root(): ...`).
+* Запускаем сервер в режиме разработки (`uvicorn main:app --reload`).
diff --git a/docs/ru/docs/tutorial/index.md b/docs/ru/docs/tutorial/index.md
new file mode 100644
index 000000000..4277a6c4f
--- /dev/null
+++ b/docs/ru/docs/tutorial/index.md
@@ -0,0 +1,80 @@
+# Учебник - Руководство пользователя - Введение
+
+В этом руководстве шаг за шагом показано, как использовать **FastApi** с большинством его функций.
+
+Каждый раздел постепенно основывается на предыдущих, но он структурирован по отдельным темам, так что вы можете перейти непосредственно к конкретной теме для решения ваших конкретных потребностей в API.
+
+Он также создан для использования в качестве будущего справочника.
+
+Так что вы можете вернуться и посмотреть именно то, что вам нужно.
+
+## Запустите код
+
+Все блоки кода можно копировать и использовать напрямую (на самом деле это проверенные файлы Python).
+
+Чтобы запустить любой из примеров, скопируйте код в файл `main.py` и запустите `uvicorn` с параметрами:
+
+
+
+**НАСТОЯТЕЛЬНО рекомендуется**, чтобы вы написали или скопировали код, отредактировали его и запустили локально.
+
+Использование кода в вашем редакторе — это то, что действительно показывает вам преимущества FastAPI, видя, как мало кода вам нужно написать, все проверки типов, автодополнение и т.д.
+
+---
+
+## Установка FastAPI
+
+Первый шаг — установить FastAPI.
+
+Для руководства вы, возможно, захотите установить его со всеми дополнительными зависимостями и функциями:
+
+
+
+...это также включает `uvicorn`, который вы можете использовать в качестве сервера, который запускает ваш код.
+
+!!! note "Технические детали"
+ Вы также можете установить его по частям.
+
+ Это то, что вы, вероятно, сделаете, когда захотите развернуть свое приложение в рабочей среде:
+
+ ```
+ pip install fastapi
+ ```
+
+ Также установите `uvicorn` для работы в качестве сервера:
+
+ ```
+ pip install "uvicorn[standard]"
+ ```
+
+ И то же самое для каждой из необязательных зависимостей, которые вы хотите использовать.
+
+## Продвинутое руководство пользователя
+
+Существует также **Продвинутое руководство пользователя**, которое вы сможете прочитать после руководства **Учебник - Руководство пользователя**.
+
+**Продвинутое руководство пользователя** основано на этом, использует те же концепции и учит вас некоторым дополнительным функциям.
+
+Но вы должны сначала прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас).
+
+Он разработан таким образом, что вы можете создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших потребностей, используя некоторые дополнительные идеи из **Продвинутого руководства пользователя**.
diff --git a/docs/ru/docs/tutorial/path-params-numeric-validations.md b/docs/ru/docs/tutorial/path-params-numeric-validations.md
new file mode 100644
index 000000000..0d034ef34
--- /dev/null
+++ b/docs/ru/docs/tutorial/path-params-numeric-validations.md
@@ -0,0 +1,292 @@
+# Path-параметры и валидация числовых данных
+
+Так же, как с помощью `Query` вы можете добавлять валидацию и метаданные для query-параметров, так и с помощью `Path` вы можете добавлять такую же валидацию и метаданные для path-параметров.
+
+## Импорт Path
+
+Сначала импортируйте `Path` из `fastapi`, а также импортируйте `Annotated`:
+
+=== "Python 3.10+"
+
+ ```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+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
+ ```
+
+!!! info "Информация"
+ Поддержка `Annotated` была добавлена в FastAPI начиная с версии 0.95.0 (и с этой версии рекомендуется использовать этот подход).
+
+ Если вы используете более старую версию, вы столкнётесь с ошибками при попытке использовать `Annotated`.
+
+ Убедитесь, что вы [обновили версию FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} как минимум до 0.95.1 перед тем, как использовать `Annotated`.
+
+## Определите метаданные
+
+Вы можете указать все те же параметры, что и для `Query`.
+
+Например, чтобы указать значение метаданных `title` для path-параметра `item_id`, вы можете написать:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="10"
+ {!> ../../../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.6+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
+ ```
+
+!!! note "Примечание"
+ Path-параметр всегда является обязательным, поскольку он составляет часть пути.
+
+ Поэтому следует объявить его с помощью `...`, чтобы обозначить, что этот параметр обязательный.
+
+ Тем не менее, даже если вы объявите его как `None` или установите для него значение по умолчанию, это ни на что не повлияет и параметр останется обязательным.
+
+## Задайте нужный вам порядок параметров
+
+!!! tip "Подсказка"
+ Это не имеет большого значения, если вы используете `Annotated`.
+
+Допустим, вы хотите объявить query-параметр `q` как обязательный параметр типа `str`.
+
+И если вам больше ничего не нужно указывать для этого параметра, то нет необходимости использовать `Query`.
+
+Но вам по-прежнему нужно использовать `Path` для path-параметра `item_id`. И если по какой-либо причине вы не хотите использовать `Annotated`, то могут возникнуть небольшие сложности.
+
+Если вы поместите параметр со значением по умолчанию перед другим параметром, у которого нет значения по умолчанию, то Python укажет на ошибку.
+
+Но вы можете изменить порядок параметров, чтобы параметр без значения по умолчанию (query-параметр `q`) шёл первым.
+
+Это не имеет значения для **FastAPI**. Он распознает параметры по их названиям, типам и значениям по умолчанию (`Query`, `Path`, и т.д.), ему не важен их порядок.
+
+Поэтому вы можете определить функцию так:
+
+=== "Python 3.6 без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial002.py!}
+ ```
+
+Но имейте в виду, что если вы используете `Annotated`, вы не столкнётесь с этой проблемой, так как вы не используете `Query()` или `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!}
+ ```
+
+## Задайте нужный вам порядок параметров, полезные приёмы
+
+!!! tip "Подсказка"
+ Это не имеет большого значения, если вы используете `Annotated`.
+
+Здесь описан **небольшой приём**, который может оказаться удобным, хотя часто он вам не понадобится.
+
+Если вы хотите:
+
+* объявить query-параметр `q` без `Query` и без значения по умолчанию
+* объявить path-параметр `item_id` с помощью `Path`
+* указать их в другом порядке
+* не использовать `Annotated`
+
+...то вы можете использовать специальную возможность синтаксиса Python.
+
+Передайте `*` в качестве первого параметра функции.
+
+Python не будет ничего делать с `*`, но он будет знать, что все следующие параметры являются именованными аргументами (парами ключ-значение), также известными как
, даже если у них нет значений по умолчанию.
+
+```Python hl_lines="7"
+{!../../../docs_src/path_params_numeric_validations/tutorial003.py!}
+```
+
+### Лучше с `Annotated`
+
+Имейте в виду, что если вы используете `Annotated`, то, поскольку вы не используете значений по умолчанию для параметров функции, то у вас не возникнет подобной проблемы и вам не придётся использовать `*`.
+
+=== "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!}
+ ```
+
+## Валидация числовых данных: больше или равно
+
+С помощью `Query` и `Path` (и других классов, которые мы разберём позже) вы можете добавлять ограничения для числовых данных.
+
+В этом примере при указании `ge=1`, параметр `item_id` должен быть больше или равен `1` ("`g`reater than or `e`qual").
+
+=== "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+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial004.py!}
+ ```
+
+## Валидация числовых данных: больше и меньше или равно
+
+То же самое применимо к:
+
+* `gt`: больше (`g`reater `t`han)
+* `le`: меньше или равно (`l`ess than or `e`qual)
+
+=== "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+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial005.py!}
+ ```
+
+## Валидация числовых данных: числа с плавающей точкой, больше и меньше
+
+Валидация также применима к значениям типа `float`.
+
+В этом случае становится важной возможность добавить ограничение
, поскольку в таком случае вы можете, например, создать ограничение, чтобы значение было больше `0`, даже если оно меньше `1`.
+
+Таким образом, `0.5` будет корректным значением. А `0.0` или `0` — нет.
+
+То же самое справедливо и для
.
+
+=== "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+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать версию с `Annotated` если возможно.
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial006.py!}
+ ```
+
+## Резюме
+
+С помощью `Query`, `Path` (и других классов, которые мы пока не затронули) вы можете добавлять метаданные и строковую валидацию тем же способом, как и в главе [Query-параметры и валидация строк](query-params-str-validations.md){.internal-link target=_blank}.
+
+А также вы можете добавить валидацию числовых данных:
+
+* `gt`: больше (`g`reater `t`han)
+* `ge`: больше или равно (`g`reater than or `e`qual)
+* `lt`: меньше (`l`ess `t`han)
+* `le`: меньше или равно (`l`ess than or `e`qual)
+
+!!! info "Информация"
+ `Query`, `Path` и другие классы, которые мы разберём позже, являются наследниками общего класса `Param`.
+
+ Все они используют те же параметры для дополнительной валидации и метаданных, которые вы видели ранее.
+
+!!! note "Технические детали"
+ `Query`, `Path` и другие "классы", которые вы импортируете из `fastapi`, на самом деле являются функциями, которые при вызове возвращают экземпляры одноимённых классов.
+
+ Объект `Query`, который вы импортируете, является функцией. И при вызове она возвращает экземпляр одноимённого класса `Query`.
+
+ Использование функций (вместо использования классов напрямую) нужно для того, чтобы ваш редактор не подсвечивал ошибки, связанные с их типами.
+
+ Таким образом вы можете использовать привычный вам редактор и инструменты разработки, не добавляя дополнительных конфигураций для игнорирования подобных ошибок.
diff --git a/docs/ru/docs/tutorial/path-params.md b/docs/ru/docs/tutorial/path-params.md
new file mode 100644
index 000000000..55b498ef0
--- /dev/null
+++ b/docs/ru/docs/tutorial/path-params.md
@@ -0,0 +1,251 @@
+# Path-параметры
+
+Вы можете определить "параметры" или "переменные" пути, используя синтаксис форматированных строк Python:
+
+```Python hl_lines="6-7"
+{!../../../docs_src/path_params/tutorial001.py!}
+```
+
+Значение параметра пути `item_id` будет передано в функцию в качестве аргумента `item_id`.
+
+Если запустите этот пример и перейдёте по адресу:
, то увидите ответ:
+
+```JSON
+{"item_id":"foo"}
+```
+
+## Параметры пути с типами
+
+Вы можете объявить тип параметра пути в функции, используя стандартные аннотации типов Python.
+
+```Python hl_lines="7"
+{!../../../docs_src/path_params/tutorial002.py!}
+```
+
+Здесь, `item_id` объявлен типом `int`.
+
+!!! check "Заметка"
+ Это обеспечит поддержку редактора внутри функции (проверка ошибок, автодополнение и т.п.).
+
+##
, то увидите ответ:
+
+```JSON
+{"item_id":3}
+```
+
+!!! check "Заметка"
+ Обратите внимание на значение `3`, которое получила (и вернула) функция. Это целочисленный Python `int`, а не строка `"3"`.
+
+ Используя определения типов, **FastAPI** выполняет автоматический
, то увидите интересную HTTP-ошибку:
+
+```JSON
+{
+ "detail": [
+ {
+ "loc": [
+ "path",
+ "item_id"
+ ],
+ "msg": "value is not a valid integer",
+ "type": "type_error.integer"
+ }
+ ]
+}
+```
+
+из-за того, что параметр пути `item_id` имеет значение `"foo"`, которое не является типом `int`.
+
+Та же ошибка возникнет, если вместо `int` передать `float` , например:
+
+!!! check "Заметка"
+ **FastAPI** обеспечивает проверку типов, используя всё те же определения типов.
+
+ Обратите внимание, что в тексте ошибки явно указано место не прошедшее проверку.
+
+ Это очень полезно при разработке и отладке кода, который взаимодействует с API.
+
+## Документация
+
+И теперь, когда откроете браузер по адресу:
+
+!!! check "Заметка"
+ Ещё раз, просто используя определения типов, **FastAPI** обеспечивает автоматическую интерактивную документацию (с интеграцией Swagger UI).
+
+ Обратите внимание, что параметр пути объявлен целочисленным.
+
+## Преимущества стандартизации, альтернативная документация
+
+Поскольку сгенерированная схема соответствует стандарту
, её можно использовать со множеством совместимых инструментов.
+
+Именно поэтому, FastAPI сам предоставляет альтернативную документацию API (используя ReDoc), которую можно получить по адресу:
+
+По той же причине, есть множество совместимых инструментов, включая инструменты генерации кода для многих языков.
+
+## Pydantic
+
+Вся проверка данных выполняется под капотом с помощью
. Поэтому вы можете быть уверены в качестве обработки данных.
+
+Вы можете использовать в аннотациях как простые типы данных, вроде `str`, `float`, `bool`, так и более сложные типы.
+
+Некоторые из них рассматриваются в следующих главах данного руководства.
+
+## Порядок имеет значение
+
+При создании *операций пути* можно столкнуться с ситуацией, когда путь является фиксированным.
+
+Например, `/users/me`. Предположим, что это путь для получения данных о текущем пользователе.
+
+У вас также может быть путь `/users/{user_id}`, чтобы получить данные о конкретном пользователе по его ID.
+
+Поскольку *операции пути* выполняются в порядке их объявления, необходимо, чтобы путь для `/users/me` был объявлен раньше, чем путь для `/users/{user_id}`:
+
+
+```Python hl_lines="6 11"
+{!../../../docs_src/path_params/tutorial003.py!}
+```
+
+Иначе путь для `/users/{user_id}` также будет соответствовать `/users/me`, "подразумевая", что он получает параметр `user_id` со значением `"me"`.
+
+Аналогично, вы не можете переопределить операцию с путем:
+
+```Python hl_lines="6 11"
+{!../../../docs_src/path_params/tutorial003b.py!}
+```
+
+Первый будет выполняться всегда, так как путь совпадает первым.
+
+## Предопределенные значения
+
+Что если нам нужно заранее определить допустимые *параметры пути*, которые *операция пути* может принимать? В таком случае можно использовать стандартное перечисление
Python.
+
+### Создание класса `Enum`
+
+Импортируйте `Enum` и создайте подкласс, который наследуется от `str` и `Enum`.
+
+Мы наследуемся от `str`, чтобы документация API могла понять, что значения должны быть типа `string` и отображалась правильно.
+
+Затем создайте атрибуты класса с фиксированными допустимыми значениями:
+
+```Python hl_lines="1 6-9"
+{!../../../docs_src/path_params/tutorial005.py!}
+```
+
+!!! info "Дополнительная информация"
+
начиная с версии 3.4.
+
+!!! tip "Подсказка"
+ Если интересно, то "AlexNet", "ResNet" и "LeNet" - это названия
машинного обучения.
+
+### Определение *параметра пути*
+
+Определите *параметр пути*, используя в аннотации типа класс перечисления (`ModelName`), созданный ранее:
+
+```Python hl_lines="16"
+{!../../../docs_src/path_params/tutorial005.py!}
+```
+
+### Проверьте документацию
+
+Поскольку доступные значения *параметра пути* определены заранее, интерактивная документация может наглядно их отображать:
+
+
+
+### Работа с *перечислениями* в Python
+
+Значение *параметра пути* будет *элементом перечисления*.
+
+#### Сравнение *элементов перечисления*
+
+Вы можете сравнить это значение с *элементом перечисления* класса `ModelName`:
+
+```Python hl_lines="17"
+{!../../../docs_src/path_params/tutorial005.py!}
+```
+
+#### Получение *значения перечисления*
+
+Можно получить фактическое значение (в данном случае - `str`) с помощью `model_name.value` или в общем случае `your_enum_member.value`:
+
+```Python hl_lines="20"
+{!../../../docs_src/path_params/tutorial005.py!}
+```
+
+!!! tip "Подсказка"
+ Значение `"lenet"` также можно получить с помощью `ModelName.lenet.value`.
+
+#### Возврат *элементов перечисления*
+
+Из *операции пути* можно вернуть *элементы перечисления*, даже вложенные в тело JSON (например в `dict`).
+
+Они будут преобразованы в соответствующие значения (в данном случае - строки) перед их возвратом клиенту:
+
+```Python hl_lines="18 21 23"
+{!../../../docs_src/path_params/tutorial005.py!}
+```
+Вы отправите клиенту такой JSON-ответ:
+
+```JSON
+{
+ "model_name": "alexnet",
+ "message": "Deep Learning FTW!"
+}
+```
+
+## Path-параметры, содержащие пути
+
+Предположим, что есть *операция пути* с путем `/files/{file_path}`.
+
+Но вам нужно, чтобы `file_path` сам содержал *путь*, например, `home/johndoe/myfile.txt`.
+
+Тогда URL для этого файла будет такой: `/files/home/johndoe/myfile.txt`.
+
+### Поддержка OpenAPI
+
+OpenAPI не поддерживает способов объявления *параметра пути*, содержащего внутри *путь*, так как это может привести к сценариям, которые сложно определять и тестировать.
+
+Тем не менее это можно сделать в **FastAPI**, используя один из внутренних инструментов Starlette.
+
+Документация по-прежнему будет работать, хотя и не добавит никакой информации о том, что параметр должен содержать путь.
+
+### Конвертер пути
+
+Благодаря одной из опций Starlette, можете объявить *параметр пути*, содержащий *путь*, используя URL вроде:
+
+```
+/files/{file_path:path}
+```
+
+В этом случае `file_path` - это имя параметра, а часть `:path`, указывает, что параметр должен соответствовать любому *пути*.
+
+Можете использовать так:
+
+```Python hl_lines="6"
+{!../../../docs_src/path_params/tutorial004.py!}
+```
+
+!!! tip "Подсказка"
+ Возможно, вам понадобится, чтобы параметр содержал `/home/johndoe/myfile.txt` с ведущим слэшем (`/`).
+
+ В этом случае URL будет таким: `/files//home/johndoe/myfile.txt`, с двойным слэшем (`//`) между `files` и `home`.
+
+## Резюме
+Используя **FastAPI** вместе со стандартными объявлениями типов Python (короткими и интуитивно понятными), вы получаете:
+
+* Поддержку редактора (проверку ошибок, автозаполнение и т.п.)
+* "
" данных
+* Валидацию данных
+* Автоматическую документацию API с указанием типов параметров.
+
+И объявлять типы достаточно один раз.
+
+Это, вероятно, является главным заметным преимуществом **FastAPI** по сравнению с альтернативными фреймворками (кроме
производительности).
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 (ниже
) необходимо было использовать `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` может принимать более одной аннотации метаданных, то теперь вы можете использовать ту же функцию с другими инструментами, например
. 🚀
+
+## Больше валидации
+
+Вы также можете добавить параметр `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 "Дополнительная информация"
+ Если вы ранее не сталкивались с `...`: это специальное значение,
.
+
+ Используется в 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/query-params.md b/docs/ru/docs/tutorial/query-params.md
new file mode 100644
index 000000000..68333ec56
--- /dev/null
+++ b/docs/ru/docs/tutorial/query-params.md
@@ -0,0 +1,225 @@
+# Query-параметры
+
+Когда вы объявляете параметры функции, которые не являются параметрами пути, они автоматически интерпретируются как "query"-параметры.
+
+```Python hl_lines="9"
+{!../../../docs_src/query_params/tutorial001.py!}
+```
+
+Query-параметры представляют из себя набор пар ключ-значение, которые идут после знака `?` в URL-адресе, разделенные символами `&`.
+
+Например, в этом URL-адресе:
+
+```
+http://127.0.0.1:8000/items/?skip=0&limit=10
+```
+
+...параметры запроса такие:
+
+* `skip`: со значением `0`
+* `limit`: со значением `10`
+
+Будучи частью URL-адреса, они "по умолчанию" являются строками.
+
+Но когда вы объявляете их с использованием аннотаций (в примере выше, как `int`), они конвертируются в указанный тип данных и проходят проверку на соответствие ему.
+
+Все те же правила, которые применяются к path-параметрам, также применяются и query-параметрам:
+
+* Поддержка от редактора кода (очевидно)
+*
данных
+* Проверка на соответствие данных (Валидация)
+* Автоматическая документация
+
+## Значения по умолчанию
+
+Поскольку query-параметры не являются фиксированной частью пути, они могут быть не обязательными и иметь значения по умолчанию.
+
+В примере выше значения по умолчанию равны `skip=0` и `limit=10`.
+
+Таким образом, результат перехода по URL-адресу:
+
+```
+http://127.0.0.1:8000/items/
+```
+
+будет таким же, как если перейти используя параметры по умолчанию:
+
+```
+http://127.0.0.1:8000/items/?skip=0&limit=10
+```
+
+Но если вы введёте, например:
+
+```
+http://127.0.0.1:8000/items/?skip=20
+```
+
+Значения параметров в вашей функции будут:
+
+* `skip=20`: потому что вы установили это в URL-адресе
+* `limit=10`: т.к это было значение по умолчанию
+
+## Необязательные параметры
+
+Аналогично, вы можете объявлять необязательные query-параметры, установив их значение по умолчанию, равное `None`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params/tutorial002.py!}
+ ```
+
+В этом случае, параметр `q` будет не обязательным и будет иметь значение `None` по умолчанию.
+
+!!! Важно
+ Также обратите внимание, что **FastAPI** достаточно умён чтобы заметить, что параметр `item_id` является path-параметром, а `q` нет, поэтому, это параметр запроса.
+
+## Преобразование типа параметра запроса
+
+Вы также можете объявлять параметры с типом `bool`, которые будут преобразованы соответственно:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params/tutorial003.py!}
+ ```
+
+В этом случае, если вы сделаете запрос:
+
+```
+http://127.0.0.1:8000/items/foo?short=1
+```
+
+или
+
+```
+http://127.0.0.1:8000/items/foo?short=True
+```
+
+или
+
+```
+http://127.0.0.1:8000/items/foo?short=true
+```
+
+или
+
+```
+http://127.0.0.1:8000/items/foo?short=on
+```
+
+или
+
+```
+http://127.0.0.1:8000/items/foo?short=yes
+```
+
+или в любом другом варианте написания (в верхнем регистре, с заглавной буквой, и т.п), внутри вашей функции параметр `short` будет иметь значение `True` типа данных `bool` . В противном случае - `False`.
+
+
+## Смешивание query-параметров и path-параметров
+
+Вы можете объявлять несколько query-параметров и path-параметров одновременно,**FastAPI** сам разберётся, что чем является.
+
+И вы не обязаны объявлять их в каком-либо определенном порядке.
+
+Они будут обнаружены по именам:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="6 8"
+ {!> ../../../docs_src/query_params/tutorial004_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="8 10"
+ {!> ../../../docs_src/query_params/tutorial004.py!}
+ ```
+
+## Обязательные query-параметры
+
+Когда вы объявляете значение по умолчанию для параметра, который не является path-параметром (в этом разделе, мы пока что познакомились только с path-параметрами), то это значение не является обязательным.
+
+Если вы не хотите задавать конкретное значение, но хотите сделать параметр необязательным, вы можете установить значение по умолчанию равным `None`.
+
+Но если вы хотите сделать query-параметр обязательным, вы можете просто не указывать значение по умолчанию:
+
+```Python hl_lines="6-7"
+{!../../../docs_src/query_params/tutorial005.py!}
+```
+
+Здесь параметр запроса `needy` является обязательным параметром с типом данных `str`.
+
+Если вы откроете в браузере URL-адрес, например:
+
+```
+http://127.0.0.1:8000/items/foo-item
+```
+
+...без добавления обязательного параметра `needy`, вы увидите подобного рода ошибку:
+
+```JSON
+{
+ "detail": [
+ {
+ "loc": [
+ "query",
+ "needy"
+ ],
+ "msg": "field required",
+ "type": "value_error.missing"
+ }
+ ]
+}
+```
+
+Поскольку `needy` является обязательным параметром, вам необходимо указать его в URL-адресе:
+
+```
+http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
+```
+
+...это будет работать:
+
+```JSON
+{
+ "item_id": "foo-item",
+ "needy": "sooooneedy"
+}
+```
+
+Конечно, вы можете определить некоторые параметры как обязательные, некоторые - со значением по умполчанию, а некоторые - полностью необязательные:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/query_params/tutorial006_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/query_params/tutorial006.py!}
+ ```
+
+В этом примере, у нас есть 3 параметра запроса:
+
+* `needy`, обязательный `str`.
+* `skip`, типа `int` и со значением по умолчанию `0`.
+* `limit`, необязательный `int`.
+
+!!! подсказка
+ Вы можете использовать класс `Enum` также, как ранее применяли его с [Path-параметрами](path-params.md#predefined-values){.internal-link target=_blank}.
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`, например, из библиотеки
в 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 кодах статуса и о том, для чего каждый из них предназначен, ознакомьтесь с
.
+
+## Краткие обозначения для запоминания названий кодов
+
+Рассмотрим предыдущий пример еще раз:
+
+```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/schema-extra-example.md b/docs/ru/docs/tutorial/schema-extra-example.md
new file mode 100644
index 000000000..a0363b9ba
--- /dev/null
+++ b/docs/ru/docs/tutorial/schema-extra-example.md
@@ -0,0 +1,189 @@
+# Объявление примера запроса данных
+
+Вы можете объявлять примеры данных, которые ваше приложение может получать.
+
+Вот несколько способов, как это можно сделать.
+
+## Pydantic `schema_extra`
+
+Вы можете объявить ключ `example` для модели Pydantic, используя класс `Config` и переменную `schema_extra`, как описано в
:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="13-21"
+ {!> ../../../docs_src/schema_extra_example/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="15-23"
+ {!> ../../../docs_src/schema_extra_example/tutorial001.py!}
+ ```
+
+Эта дополнительная информация будет включена в **JSON Schema** выходных данных для этой модели, и она будет использоваться в документации к API.
+
+!!! tip Подсказка
+ Вы можете использовать тот же метод для расширения JSON-схемы и добавления своей собственной дополнительной информации.
+
+ Например, вы можете использовать это для добавления дополнительной информации для пользовательского интерфейса в вашем веб-приложении и т.д.
+
+## Дополнительные аргументы поля `Field`
+
+При использовании `Field()` с моделями Pydantic, вы также можете объявлять дополнительную информацию для **JSON Schema**, передавая любые другие произвольные аргументы в функцию.
+
+Вы можете использовать это, чтобы добавить аргумент `example` для каждого поля:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="2 8-11"
+ {!> ../../../docs_src/schema_extra_example/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.6+"
+
+ ```Python hl_lines="4 10-13"
+ {!> ../../../docs_src/schema_extra_example/tutorial002.py!}
+ ```
+
+!!! warning Внимание
+ Имейте в виду, что эти дополнительные переданные аргументы не добавляют никакой валидации, только дополнительную информацию для документации.
+
+## Использование `example` и `examples` в OpenAPI
+
+При использовании любой из этих функций:
+
+* `Path()`
+* `Query()`
+* `Header()`
+* `Cookie()`
+* `Body()`
+* `Form()`
+* `File()`
+
+вы также можете добавить аргумент, содержащий `example` или группу `examples` с дополнительной информацией, которая будет добавлена в **OpenAPI**.
+
+### Параметр `Body` с аргументом `example`
+
+Здесь мы передаём аргумент `example`, как пример данных ожидаемых в параметре `Body()`:
+
+=== "Python 3.10+"
+
+ ```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+ non-Annotated"
+
+ !!! tip Заметка
+ Рекомендуется использовать версию с `Annotated`, если это возможно.
+
+ ```Python hl_lines="18-23"
+ {!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip Заметка
+ Рекомендуется использовать версию с `Annotated`, если это возможно.
+
+ ```Python hl_lines="20-25"
+ {!> ../../../docs_src/schema_extra_example/tutorial003.py!}
+ ```
+
+### Аргумент "example" в UI документации
+
+С любым из вышеуказанных методов это будет выглядеть так в `/docs`:
+
+
+
+### `Body` с аргументом `examples`
+
+В качестве альтернативы одному аргументу `example`, вы можете передавать `examples` используя тип данных `dict` с **несколькими примерами**, каждый из которых содержит дополнительную информацию, которая также будет добавлена в **OpenAPI**.
+
+Ключи `dict` указывают на каждый пример, а значения для каждого из них - на еще один тип `dict` с дополнительной информацией.
+
+Каждый конкретный пример типа `dict` в аргументе `examples` может содержать:
+
+* `summary`: Краткое описание для примера.
+* `description`: Полное описание, которое может содержать текст в формате Markdown.
+* `value`: Это конкретный пример, который отображается, например, в виде типа `dict`.
+* `externalValue`: альтернатива параметру `value`, URL-адрес, указывающий на пример. Хотя это может не поддерживаться таким же количеством инструментов разработки и тестирования API, как параметр `value`.
+
+=== "Python 3.10+"
+
+ ```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+ non-Annotated"
+
+ !!! tip Заметка
+ Рекомендуется использовать версию с `Annotated`, если это возможно.
+
+ ```Python hl_lines="19-45"
+ {!> ../../../docs_src/schema_extra_example/tutorial004_py310.py!}
+ ```
+
+=== "Python 3.6+ non-Annotated"
+
+ !!! tip Заметка
+ Рекомендуется использовать версию с `Annotated`, если это возможно.
+
+ ```Python hl_lines="21-47"
+ {!> ../../../docs_src/schema_extra_example/tutorial004.py!}
+ ```
+
+### Аргумент "examples" в UI документации
+
+С аргументом `examples`, добавленным в `Body()`, страница документации `/docs` будет выглядеть так:
+
+
+
+## Технические Детали
+
+!!! warning Внимание
+ Эти технические детали относятся к стандартам **JSON Schema** и **OpenAPI**.
+
+ Если предложенные выше идеи уже работают для вас, возможно этого будет достаточно и эти детали вам не потребуются, можете спокойно их пропустить.
+
+Когда вы добавляете пример внутрь модели Pydantic, используя `schema_extra` или `Field(example="something")`, этот пример добавляется в **JSON Schema** для данной модели Pydantic.
+
+И эта **JSON Schema** модели Pydantic включается в **OpenAPI** вашего API, а затем используется в UI документации.
+
+Поля `example` как такового не существует в стандартах **JSON Schema**. В последних версиях JSON-схемы определено поле
, но OpenAPI 3.0.3 основан на более старой версии JSON-схемы, которая не имела поля `examples`.
+
+Таким образом, OpenAPI 3.0.3 определяет своё собственное поле
для модифицированной версии **JSON Schema**, которую он использует чтобы достичь той же цели (однако это именно поле `example`, а не `examples`), и именно это используется API в UI документации (с интеграцией Swagger UI).
+
+Итак, хотя поле `example` не является частью JSON-схемы, оно является частью настраиваемой версии JSON-схемы в OpenAPI, и именно это поле будет использоваться в UI документации.
+
+Однако, когда вы используете поле `example` или `examples` с любой другой функцией (`Query()`, `Body()`, и т.д.), эти примеры не добавляются в JSON-схему, которая описывает эти данные (даже в собственную версию JSON-схемы OpenAPI), они добавляются непосредственно в объявление *операции пути* в OpenAPI (вне частей OpenAPI, которые используют JSON-схему).
+
+Для функций `Path()`, `Query()`, `Header()`, и `Cookie()`, аргументы `example` или `examples` добавляются в
.
+
+И для функций `Body()`, `File()` и `Form()` аргументы `example` или `examples` аналогично добавляются в
.
+
+С другой стороны, существует более новая версия OpenAPI: **3.1.0**, недавно выпущенная. Она основана на последней версии JSON-схемы и большинство модификаций из OpenAPI JSON-схемы удалены в обмен на новые возможности из последней версии JSON-схемы, так что все эти мелкие отличия устранены. Тем не менее, Swagger UI в настоящее время не поддерживает OpenAPI 3.1.0, поэтому пока лучше продолжать использовать вышеупомянутые методы.
diff --git a/docs/ru/docs/tutorial/static-files.md b/docs/ru/docs/tutorial/static-files.md
new file mode 100644
index 000000000..ec09eb5a3
--- /dev/null
+++ b/docs/ru/docs/tutorial/static-files.md
@@ -0,0 +1,40 @@
+# Статические Файлы
+
+Вы можете предоставлять статические файлы автоматически из директории, используя `StaticFiles`.
+
+## Использование `StaticFiles`
+
+* Импортируйте `StaticFiles`.
+* "Примонтируйте" экземпляр `StaticFiles()` с указанием определенной директории.
+
+```Python hl_lines="2 6"
+{!../../../docs_src/static_files/tutorial001.py!}
+```
+
+!!! заметка "Технические детали"
+ Вы также можете использовать `from starlette.staticfiles import StaticFiles`.
+
+ **FastAPI** предоставляет `starlette.staticfiles` под псевдонимом `fastapi.staticfiles`, просто для вашего удобства, как разработчика. Но на самом деле это берётся напрямую из библиотеки Starlette.
+
+### Что такое "Монтирование"
+
+"Монтирование" означает добавление полноценного "независимого" приложения в определенную директорию, которое затем обрабатывает все подпути.
+
+Это отличается от использования `APIRouter`, так как примонтированное приложение является полностью независимым.
+OpenAPI и документация из вашего главного приложения не будет содержать ничего из примонтированного приложения, и т.д.
+
+Вы можете прочитать больше об этом в **Расширенном руководстве пользователя**.
+
+## Детали
+
+Первый параметр `"/static"` относится к подпути, по которому это "подприложение" будет "примонтировано". Таким образом, любой путь начинающийся со `"/static"` будет обработан этим приложением.
+
+Параметр `directory="static"` относится к имени директории, которая содержит ваши статические файлы.
+
+`name="static"` даёт имя маршруту, которое может быть использовано внутри **FastAPI**.
+
+Все эти параметры могут отличаться от "`static`", настройте их в соответствии с вашими нуждами и конкретными деталями вашего собственного приложения.
+
+## Больше информации
+
+Для получения дополнительной информации о деталях и настройках ознакомьтесь с
.
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 @@
+# Тестирование
+
+Благодаря
, тестировать приложения **FastAPI** легко и приятно.
+
+Тестирование основано на библиотеке
, которая в свою очередь основана на библиотеке Requests, так что все действия знакомы и интуитивно понятны.
+
+Используя эти инструменты, Вы можете напрямую задействовать
с **FastAPI**.
+
+## Использование класса `TestClient`
+
+!!! info "Информация"
+ Для использования класса `TestClient` необходимо установить библиотеку
.
+
+ Например, так: `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` ознакомьтесь с
.
+
+!!! info "Информация"
+ Обратите внимание, что `TestClient` принимает данные, которые можно конвертировать в JSON, но не модели Pydantic.
+
+ Если в Ваших тестах есть модели Pydantic и Вы хотите отправить их в тестируемое приложение, то можете использовать функцию `jsonable_encoder`, описанную на странице [Кодировщик совместимый с JSON](encoder.md){.internal-link target=_blank}.
+
+## Запуск тестов
+
+Далее Вам нужно установить `pytest`:
+
+
+
+Он автоматически найдёт все файлы и тесты, выполнит их и предоставит Вам отчёт о результатах тестирования.
+
+Запустите тесты командой `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..9fb56ce1b 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,36 @@ nav:
- fastapi-people.md
- python-types.md
- Учебник - руководство пользователя:
+ - tutorial/index.md
+ - tutorial/first-steps.md
+ - tutorial/path-params.md
+ - tutorial/query-params-str-validations.md
+ - tutorial/path-params-numeric-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
+ - tutorial/query-params.md
+ - tutorial/body-multiple-params.md
+ - tutorial/static-files.md
+ - tutorial/debugging.md
+ - tutorial/schema-extra-example.md
- async.md
- Развёртывание:
- deployment/index.md
- deployment/versions.md
+ - deployment/concepts.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 +119,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 +140,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 +154,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -129,6 +164,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -141,6 +178,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/mkdocs.yml b/docs/tr/mkdocs.yml
index 5904f71f9..5811f793e 100644
--- a/docs/tr/mkdocs.yml
+++ b/docs/tr/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/
@@ -85,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
@@ -106,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/
@@ -116,6 +125,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -124,6 +135,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -136,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/advanced/response-change-status-code.md b/docs/zh/docs/advanced/response-change-status-code.md
new file mode 100644
index 000000000..a289cf201
--- /dev/null
+++ b/docs/zh/docs/advanced/response-change-status-code.md
@@ -0,0 +1,31 @@
+# 响应 - 更改状态码
+
+你可能之前已经了解到,你可以设置默认的[响应状态码](../tutorial/response-status-code.md){.internal-link target=_blank}。
+
+但在某些情况下,你需要返回一个不同于默认值的状态码。
+
+## 使用场景
+
+例如,假设你想默认返回一个HTTP状态码为“OK”`200`。
+
+但如果数据不存在,你想创建它,并返回一个HTTP状态码为“CREATED”`201`。
+
+但你仍然希望能够使用`response_model`过滤和转换你返回的数据。
+
+对于这些情况,你可以使用一个`Response`参数。
+
+## 使用 `Response` 参数
+
+你可以在你的*路径操作函数*中声明一个`Response`类型的参数(就像你可以为cookies和头部做的那样)。
+
+然后你可以在这个*临时*响应对象中设置`status_code`。
+
+```Python hl_lines="1 9 12"
+{!../../../docs_src/response_change_status_code/tutorial001.py!}
+```
+
+然后你可以像平常一样返回任何你需要的对象(例如一个`dict`或者一个数据库模型)。如果你声明了一个`response_model`,它仍然会被用来过滤和转换你返回的对象。
+
+**FastAPI**将使用这个临时响应来提取状态码(也包括cookies和头部),并将它们放入包含你返回的值的最终响应中,该响应由任何`response_model`过滤。
+
+你也可以在依赖项中声明`Response`参数,并在其中设置状态码。但请注意,最后设置的状态码将会生效。
diff --git a/docs/zh/docs/advanced/response-headers.md b/docs/zh/docs/advanced/response-headers.md
new file mode 100644
index 000000000..85dab15ac
--- /dev/null
+++ b/docs/zh/docs/advanced/response-headers.md
@@ -0,0 +1,39 @@
+# 响应头
+
+## 使用 `Response` 参数
+
+你可以在你的*路径操作函数*中声明一个`Response`类型的参数(就像你可以为cookies做的那样)。
+
+然后你可以在这个*临时*响应对象中设置头部。
+```Python hl_lines="1 7-8"
+{!../../../docs_src/response_headers/tutorial002.py!}
+```
+
+然后你可以像平常一样返回任何你需要的对象(例如一个`dict`或者一个数据库模型)。如果你声明了一个`response_model`,它仍然会被用来过滤和转换你返回的对象。
+
+**FastAPI**将使用这个临时响应来提取头部(也包括cookies和状态码),并将它们放入包含你返回的值的最终响应中,该响应由任何`response_model`过滤。
+
+你也可以在依赖项中声明`Response`参数,并在其中设置头部(和cookies)。
+
+## 直接返回 `Response`
+
+你也可以在直接返回`Response`时添加头部。
+
+按照[直接返回响应](response-directly.md){.internal-link target=_blank}中所述创建响应,并将头部作为附加参数传递:
+```Python hl_lines="10-12"
+{!../../../docs_src/response_headers/tutorial001.py!}
+```
+
+
+!!! 注意 "技术细节"
+ 你也可以使用`from starlette.responses import Response`或`from starlette.responses import JSONResponse`。
+
+ **FastAPI**提供了与`fastapi.responses`相同的`starlette.responses`,只是为了方便开发者。但是,大多数可用的响应都直接来自Starlette。
+
+ 由于`Response`经常用于设置头部和cookies,因此**FastAPI**还在`fastapi.Response`中提供了它。
+
+## 自定义头部
+
+请注意,可以使用'X-'前缀添加自定义专有头部。
+
+但是,如果你有自定义头部,你希望浏览器中的客户端能够看到它们,你需要将它们添加到你的CORS配置中(在[CORS(跨源资源共享)](../tutorial/cors.md){.internal-link target=_blank}中阅读更多),使用在
中记录的`expose_headers`参数。
diff --git a/docs/zh/docs/contributing.md b/docs/zh/docs/contributing.md
index 36c3631c4..4ebd67315 100644
--- a/docs/zh/docs/contributing.md
+++ b/docs/zh/docs/contributing.md
@@ -97,7 +97,7 @@ $ python -m venv env
```console
-$ pip install -e ."[dev,doc,test]"
+$ pip install -r requirements.txt
---> 100%
```
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/docs/tutorial/static-files.md b/docs/zh/docs/tutorial/static-files.md
new file mode 100644
index 000000000..e7c5c3f0a
--- /dev/null
+++ b/docs/zh/docs/tutorial/static-files.md
@@ -0,0 +1,39 @@
+# 静态文件
+
+您可以使用 `StaticFiles`从目录中自动提供静态文件。
+
+## 使用`StaticFiles`
+
+* 导入`StaticFiles`。
+* "挂载"(Mount) 一个 `StaticFiles()` 实例到一个指定路径。
+
+```Python hl_lines="2 6"
+{!../../../docs_src/static_files/tutorial001.py!}
+```
+
+!!! note "技术细节"
+ 你也可以用 `from starlette.staticfiles import StaticFiles`。
+
+ **FastAPI** 提供了和 `starlette.staticfiles` 相同的 `fastapi.staticfiles` ,只是为了方便你,开发者。但它确实来自Starlette。
+
+### 什么是"挂载"(Mounting)
+
+"挂载" 表示在特定路径添加一个完全"独立的"应用,然后负责处理所有子路径。
+
+这与使用`APIRouter`不同,因为安装的应用程序是完全独立的。OpenAPI和来自你主应用的文档不会包含已挂载应用的任何东西等等。
+
+你可以在**高级用户指南**中了解更多。
+
+## 细节
+
+这个 "子应用" 会被 "挂载" 到第一个 `"/static"` 指向的子路径。因此,任何以`"/static"`开头的路径都会被它处理。
+
+ `directory="static"` 指向包含你的静态文件的目录名字。
+
+`name="static"` 提供了一个能被**FastAPI**内部使用的名字。
+
+所有这些参数可以不同于"`static`",根据你应用的需要和具体细节调整它们。
+
+## 更多信息
+
+更多细节和选择查阅
Starlette's docs about Static Files.
diff --git a/docs/zh/mkdocs.yml b/docs/zh/mkdocs.yml
index f4c3c0ec1..522c83766 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/
@@ -103,6 +108,7 @@ nav:
- tutorial/sql-databases.md
- tutorial/bigger-applications.md
- tutorial/metadata.md
+ - tutorial/static-files.md
- tutorial/debugging.md
- 高级用户指南:
- advanced/index.md
@@ -111,6 +117,8 @@ nav:
- advanced/response-directly.md
- advanced/custom-response.md
- advanced/response-cookies.md
+ - advanced/response-change-status-code.md
+ - advanced/response-headers.md
- advanced/wsgi.md
- contributing.md
- help-fastapi.md
@@ -137,7 +145,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 +166,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 +180,8 @@ extra:
name: fr - français
- link: /he/
name: he
+ - link: /hy/
+ name: hy
- link: /id/
name: id
- link: /it/
@@ -176,6 +190,8 @@ extra:
name: ja - 日本語
- link: /ko/
name: ko - 한국어
+ - link: /lo/
+ name: lo - ພາສາລາວ
- link: /nl/
name: nl
- link: /pl/
@@ -188,6 +204,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/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/docs_src/wsgi/tutorial001.py b/docs_src/wsgi/tutorial001.py
index 500ecf883..7f27a85a1 100644
--- a/docs_src/wsgi/tutorial001.py
+++ b/docs_src/wsgi/tutorial001.py
@@ -1,6 +1,7 @@
from fastapi import FastAPI
from fastapi.middleware.wsgi import WSGIMiddleware
-from flask import Flask, escape, request
+from flask import Flask, request
+from markupsafe import escape
flask_app = Flask(__name__)
diff --git a/fastapi/__init__.py b/fastapi/__init__.py
index 07ed78ffa..46a056363 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.89.1"
+__version__ = "0.97.0"
from starlette import status as status
diff --git a/fastapi/applications.py b/fastapi/applications.py
index 36dc2605d..298aca921 100644
--- a/fastapi/applications.py
+++ b/fastapi/applications.py
@@ -9,6 +9,7 @@ from typing import (
Optional,
Sequence,
Type,
+ TypeVar,
Union,
)
@@ -18,8 +19,9 @@ from fastapi.encoders import DictIntStrAny, SetIntStr
from fastapi.exception_handlers import (
http_exception_handler,
request_validation_exception_handler,
+ websocket_request_validation_exception_handler,
)
-from fastapi.exceptions import RequestValidationError
+from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
from fastapi.logger import logger
from fastapi.middleware.asyncexitstack import AsyncExitStackMiddleware
from fastapi.openapi.docs import (
@@ -35,17 +37,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 +75,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 +92,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 +130,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,
@@ -139,11 +146,16 @@ class FastAPI(Starlette):
self.exception_handlers.setdefault(
RequestValidationError, request_validation_exception_handler
)
+ self.exception_handlers.setdefault(
+ WebSocketRequestValidationError,
+ # Starlette still has incorrect type specification for the handlers
+ websocket_request_validation_exception_handler, # type: ignore
+ )
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:
@@ -389,15 +401,34 @@ class FastAPI(Starlette):
return decorator
def add_api_websocket_route(
- self, path: str, endpoint: Callable[..., Any], name: Optional[str] = None
+ self,
+ path: str,
+ endpoint: Callable[..., Any],
+ name: Optional[str] = None,
+ *,
+ dependencies: Optional[Sequence[Depends]] = None,
) -> None:
- self.router.add_api_websocket_route(path, endpoint, name=name)
+ self.router.add_api_websocket_route(
+ path,
+ endpoint,
+ name=name,
+ dependencies=dependencies,
+ )
def websocket(
- self, path: str, name: Optional[str] = None
+ self,
+ path: str,
+ name: Optional[str] = None,
+ *,
+ dependencies: Optional[Sequence[Depends]] = None,
) -> Callable[[DecoratedCallable], DecoratedCallable]:
def decorator(func: DecoratedCallable) -> DecoratedCallable:
- self.add_api_websocket_route(path, func, name=name)
+ self.add_api_websocket_route(
+ path,
+ func,
+ name=name,
+ dependencies=dependencies,
+ )
return func
return decorator
@@ -870,3 +901,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 16947ceca..2741dcb99 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,
@@ -48,7 +48,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
@@ -56,6 +56,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,
)
@@ -322,122 +323,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:
@@ -720,7 +799,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/exception_handlers.py b/fastapi/exception_handlers.py
index 4d7ea5ec2..6c2ba7fed 100644
--- a/fastapi/exception_handlers.py
+++ b/fastapi/exception_handlers.py
@@ -1,10 +1,11 @@
from fastapi.encoders import jsonable_encoder
-from fastapi.exceptions import RequestValidationError
+from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
from fastapi.utils import is_body_allowed_for_status_code
+from fastapi.websockets import WebSocket
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.responses import JSONResponse, Response
-from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
+from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY, WS_1008_POLICY_VIOLATION
async def http_exception_handler(request: Request, exc: HTTPException) -> Response:
@@ -23,3 +24,11 @@ async def request_validation_exception_handler(
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
content={"detail": jsonable_encoder(exc.errors())},
)
+
+
+async def websocket_request_validation_exception_handler(
+ websocket: WebSocket, exc: WebSocketRequestValidationError
+) -> None:
+ await websocket.close(
+ code=WS_1008_POLICY_VIOLATION, reason=jsonable_encoder(exc.errors())
+ )
diff --git a/fastapi/exceptions.py b/fastapi/exceptions.py
index ca097b1ce..cac5330a2 100644
--- a/fastapi/exceptions.py
+++ b/fastapi/exceptions.py
@@ -11,7 +11,7 @@ class HTTPException(StarletteHTTPException):
self,
status_code: int,
detail: Any = None,
- headers: Optional[Dict[str, Any]] = None,
+ headers: Optional[Dict[str, str]] = None,
) -> None:
super().__init__(status_code=status_code, detail=detail, headers=headers)
diff --git a/fastapi/middleware/asyncexitstack.py b/fastapi/middleware/asyncexitstack.py
index 503a68ac7..30a0ae626 100644
--- a/fastapi/middleware/asyncexitstack.py
+++ b/fastapi/middleware/asyncexitstack.py
@@ -10,19 +10,16 @@ class AsyncExitStackMiddleware:
self.context_name = context_name
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
- if AsyncExitStack:
- dependency_exception: Optional[Exception] = None
- async with AsyncExitStack() as stack:
- scope[self.context_name] = stack
- try:
- await self.app(scope, receive, send)
- except Exception as e:
- dependency_exception = e
- raise e
- if dependency_exception:
- # This exception was possibly handled by the dependency but it should
- # still bubble up so that the ServerErrorMiddleware can return a 500
- # or the ExceptionMiddleware can catch and handle any other exceptions
- raise dependency_exception
- else:
- await self.app(scope, receive, send) # pragma: no cover
+ dependency_exception: Optional[Exception] = None
+ async with AsyncExitStack() as stack:
+ scope[self.context_name] = stack
+ try:
+ await self.app(scope, receive, send)
+ except Exception as e:
+ dependency_exception = e
+ raise e
+ if dependency_exception:
+ # This exception was possibly handled by the dependency but it should
+ # still bubble up so that the ServerErrorMiddleware can return a 500
+ # or the ExceptionMiddleware can catch and handle any other exceptions
+ raise dependency_exception
diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py
index 35aa1672b..81a24f389 100644
--- a/fastapi/openapi/models.py
+++ b/fastapi/openapi/models.py
@@ -3,6 +3,7 @@ from typing import Any, Callable, Dict, Iterable, List, Optional, Union
from fastapi.logger import logger
from pydantic import AnyUrl, BaseModel, Field
+from typing_extensions import Literal
try:
import email_validator # type: ignore
@@ -108,14 +109,14 @@ class Schema(BaseModel):
exclusiveMaximum: Optional[float] = None
minimum: Optional[float] = None
exclusiveMinimum: Optional[float] = None
- maxLength: Optional[int] = Field(default=None, gte=0)
- minLength: Optional[int] = Field(default=None, gte=0)
+ maxLength: Optional[int] = Field(default=None, ge=0)
+ minLength: Optional[int] = Field(default=None, ge=0)
pattern: Optional[str] = None
- maxItems: Optional[int] = Field(default=None, gte=0)
- minItems: Optional[int] = Field(default=None, gte=0)
+ maxItems: Optional[int] = Field(default=None, ge=0)
+ minItems: Optional[int] = Field(default=None, ge=0)
uniqueItems: Optional[bool] = None
- maxProperties: Optional[int] = Field(default=None, gte=0)
- minProperties: Optional[int] = Field(default=None, gte=0)
+ maxProperties: Optional[int] = Field(default=None, ge=0)
+ minProperties: Optional[int] = Field(default=None, ge=0)
required: Optional[List[str]] = None
enum: Optional[List[Any]] = None
type: Optional[str] = None
@@ -298,18 +299,18 @@ class APIKeyIn(Enum):
class APIKey(SecurityBase):
- type_ = Field(SecuritySchemeType.apiKey, alias="type")
+ type_: SecuritySchemeType = Field(default=SecuritySchemeType.apiKey, alias="type")
in_: APIKeyIn = Field(alias="in")
name: str
class HTTPBase(SecurityBase):
- type_ = Field(SecuritySchemeType.http, alias="type")
+ type_: SecuritySchemeType = Field(default=SecuritySchemeType.http, alias="type")
scheme: str
class HTTPBearer(HTTPBase):
- scheme = "bearer"
+ scheme: Literal["bearer"] = "bearer"
bearerFormat: Optional[str] = None
@@ -349,12 +350,14 @@ class OAuthFlows(BaseModel):
class OAuth2(SecurityBase):
- type_ = Field(SecuritySchemeType.oauth2, alias="type")
+ type_: SecuritySchemeType = Field(default=SecuritySchemeType.oauth2, alias="type")
flows: OAuthFlows
class OpenIdConnect(SecurityBase):
- type_ = Field(SecuritySchemeType.openIdConnect, alias="type")
+ type_: SecuritySchemeType = Field(
+ default=SecuritySchemeType.openIdConnect, alias="type"
+ )
openIdConnectUrl: str
diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py
index 86e15b46d..6d736647b 100644
--- a/fastapi/openapi/utils.py
+++ b/fastapi/openapi/utils.py
@@ -181,7 +181,7 @@ def get_openapi_operation_metadata(
file_name = getattr(route.endpoint, "__globals__", {}).get("__file__")
if file_name:
message += f" at {file_name}"
- warnings.warn(message)
+ warnings.warn(message, stacklevel=1)
operation_ids.add(operation_id)
operation["operationId"] = operation_id
if route.deprecated:
@@ -332,10 +332,8 @@ def get_openapi_path(
openapi_response["description"] = description
http422 = str(HTTP_422_UNPROCESSABLE_ENTITY)
if (all_route_params or route.body_field) and not any(
- [
- status in operation["responses"]
- for status in [http422, "4XX", "default"]
- ]
+ status in operation["responses"]
+ for status in [http422, "4XX", "default"]
):
operation["responses"][http422] = {
"description": "Validation Error",
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/responses.py b/fastapi/responses.py
index 88dba96e8..c0a13b755 100644
--- a/fastapi/responses.py
+++ b/fastapi/responses.py
@@ -27,8 +27,6 @@ class UJSONResponse(JSONResponse):
class ORJSONResponse(JSONResponse):
- media_type = "application/json"
-
def render(self, content: Any) -> bytes:
assert orjson is not None, "orjson must be installed to use ORJSONResponse"
return orjson.dumps(
diff --git a/fastapi/routing.py b/fastapi/routing.py
index f131fa903..ec8af99b3 100644
--- a/fastapi/routing.py
+++ b/fastapi/routing.py
@@ -30,7 +30,11 @@ from fastapi.dependencies.utils import (
solve_dependencies,
)
from fastapi.encoders import DictIntStrAny, SetIntStr, jsonable_encoder
-from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
+from fastapi.exceptions import (
+ FastAPIError,
+ RequestValidationError,
+ WebSocketRequestValidationError,
+)
from fastapi.types import DecoratedCallable
from fastapi.utils import (
create_cloned_field,
@@ -48,16 +52,16 @@ from starlette.concurrency import run_in_threadpool
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.responses import JSONResponse, Response
-from starlette.routing import BaseRoute, Match
-from starlette.routing import Mount as Mount # noqa
from starlette.routing import (
+ BaseRoute,
+ Match,
compile_path,
get_name,
request_response,
websocket_session,
)
-from starlette.status import WS_1008_POLICY_VIOLATION
-from starlette.types import ASGIApp, Scope
+from starlette.routing import Mount as Mount # noqa
+from starlette.types import ASGIApp, Lifespan, Scope
from starlette.websockets import WebSocket
@@ -283,7 +287,6 @@ def get_websocket_app(
)
values, errors, _, _2, _3 = solved_result
if errors:
- await websocket.close(code=WS_1008_POLICY_VIOLATION)
raise WebSocketRequestValidationError(errors)
assert dependant.call is not None, "dependant.call must be a function"
await dependant.call(**values)
@@ -298,13 +301,21 @@ class APIWebSocketRoute(routing.WebSocketRoute):
endpoint: Callable[..., Any],
*,
name: Optional[str] = None,
+ dependencies: Optional[Sequence[params.Depends]] = None,
dependency_overrides_provider: Optional[Any] = None,
) -> None:
self.path = path
self.endpoint = endpoint
self.name = get_name(endpoint) if name is None else name
+ self.dependencies = list(dependencies or [])
self.path_regex, self.path_format, self.param_convertors = compile_path(path)
self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
+ for depends in self.dependencies[::-1]:
+ self.dependant.dependencies.insert(
+ 0,
+ get_parameterless_sub_dependant(depends=depends, path=self.path_format),
+ )
+
self.app = websocket_session(
get_websocket_app(
dependant=self.dependant,
@@ -418,10 +429,7 @@ class APIRoute(routing.Route):
else:
self.response_field = None # type: ignore
self.secure_cloned_response_field = None
- if dependencies:
- self.dependencies = list(dependencies)
- else:
- self.dependencies = []
+ self.dependencies = list(dependencies or [])
self.description = description or inspect.cleandoc(self.endpoint.__doc__ or "")
# if a "form feed" character (page break) is found in the description text,
# truncate description text to the content preceding the first "form feed"
@@ -492,6 +500,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(
@@ -504,6 +515,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 '/'"
@@ -512,7 +524,7 @@ class APIRouter(routing.Router):
), "A path prefix must not end with '/', as the routes will start with '/'"
self.prefix = prefix
self.tags: List[Union[str, Enum]] = tags or []
- self.dependencies = list(dependencies or []) or []
+ self.dependencies = list(dependencies or [])
self.deprecated = deprecated
self.include_in_schema = include_in_schema
self.responses = responses or {}
@@ -522,6 +534,25 @@ class APIRouter(routing.Router):
self.default_response_class = default_response_class
self.generate_unique_id_function = generate_unique_id_function
+ 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,
@@ -667,21 +698,46 @@ class APIRouter(routing.Router):
return decorator
def add_api_websocket_route(
- self, path: str, endpoint: Callable[..., Any], name: Optional[str] = None
+ self,
+ path: str,
+ endpoint: Callable[..., Any],
+ name: Optional[str] = None,
+ *,
+ dependencies: Optional[Sequence[params.Depends]] = None,
) -> None:
+ current_dependencies = self.dependencies.copy()
+ if dependencies:
+ current_dependencies.extend(dependencies)
+
route = APIWebSocketRoute(
self.prefix + path,
endpoint=endpoint,
name=name,
+ dependencies=current_dependencies,
dependency_overrides_provider=self.dependency_overrides_provider,
)
self.routes.append(route)
def websocket(
- self, path: str, name: Optional[str] = None
+ self,
+ path: str,
+ name: Optional[str] = None,
+ *,
+ dependencies: Optional[Sequence[params.Depends]] = None,
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ def decorator(func: DecoratedCallable) -> DecoratedCallable:
+ self.add_api_websocket_route(
+ path, func, name=name, dependencies=dependencies
+ )
+ return func
+
+ return decorator
+
+ def websocket_route(
+ self, path: str, name: Union[str, None] = None
) -> Callable[[DecoratedCallable], DecoratedCallable]:
def decorator(func: DecoratedCallable) -> DecoratedCallable:
- self.add_api_websocket_route(path, func, name=name)
+ self.add_websocket_route(path, func, name=name)
return func
return decorator
@@ -712,7 +768,7 @@ class APIRouter(routing.Router):
path = getattr(r, "path") # noqa: B009
name = getattr(r, "name", "unknown")
if path is not None and not path:
- raise Exception(
+ raise FastAPIError(
f"Prefix and path cannot be both empty (path operation: {name})"
)
if responses is None:
@@ -787,8 +843,16 @@ class APIRouter(routing.Router):
name=route.name,
)
elif isinstance(route, APIWebSocketRoute):
+ current_dependencies = []
+ if dependencies:
+ current_dependencies.extend(dependencies)
+ if route.dependencies:
+ current_dependencies.extend(route.dependencies)
self.add_api_websocket_route(
- prefix + route.path, route.endpoint, name=route.name
+ prefix + route.path,
+ route.endpoint,
+ dependencies=current_dependencies,
+ name=route.name,
)
elif isinstance(route, routing.WebSocketRoute):
self.add_websocket_route(
@@ -1220,7 +1284,6 @@ class APIRouter(routing.Router):
generate_unique_id
),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
-
return self.api_route(
path=path,
response_model=response_model,
@@ -1247,3 +1310,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..8b2c5c080 100644
--- a/fastapi/security/api_key.py
+++ b/fastapi/security/api_key.py
@@ -18,10 +18,12 @@ 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
+ **{"in": APIKeyIn.query}, # type: ignore[arg-type]
+ name=name,
+ description=description,
)
self.scheme_name = scheme_name or self.__class__.__name__
self.auto_error = auto_error
@@ -45,10 +47,12 @@ 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
+ **{"in": APIKeyIn.header}, # type: ignore[arg-type]
+ name=name,
+ description=description,
)
self.scheme_name = scheme_name or self.__class__.__name__
self.auto_error = auto_error
@@ -72,10 +76,12 @@ 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
+ **{"in": APIKeyIn.cookie}, # type: ignore[arg-type]
+ name=name,
+ description=description,
)
self.scheme_name = scheme_name or self.__class__.__name__
self.auto_error = auto_error
diff --git a/fastapi/security/http.py b/fastapi/security/http.py
index 8b677299d..8fc0aafd9 100644
--- a/fastapi/security/http.py
+++ b/fastapi/security/http.py
@@ -73,11 +73,6 @@ class HTTPBasic(HTTPBase):
unauthorized_headers = {"WWW-Authenticate": f'Basic realm="{self.realm}"'}
else:
unauthorized_headers = {"WWW-Authenticate": "Basic"}
- invalid_user_credentials_exc = HTTPException(
- status_code=HTTP_401_UNAUTHORIZED,
- detail="Invalid authentication credentials",
- headers=unauthorized_headers,
- )
if not authorization or scheme.lower() != "basic":
if self.auto_error:
raise HTTPException(
@@ -87,6 +82,11 @@ class HTTPBasic(HTTPBase):
)
else:
return None
+ invalid_user_credentials_exc = HTTPException(
+ status_code=HTTP_401_UNAUTHORIZED,
+ detail="Invalid authentication credentials",
+ headers=unauthorized_headers,
+ )
try:
data = b64decode(param).decode("ascii")
except (ValueError, UnicodeDecodeError, binascii.Error):
diff --git a/fastapi/security/oauth2.py b/fastapi/security/oauth2.py
index eb6b4277c..938dec37c 100644
--- a/fastapi/security/oauth2.py
+++ b/fastapi/security/oauth2.py
@@ -1,4 +1,4 @@
-from typing import Any, Dict, List, Optional, Union
+from typing import Any, Dict, List, Optional, Union, cast
from fastapi.exceptions import HTTPException
from fastapi.openapi.models import OAuth2 as OAuth2Model
@@ -119,9 +119,11 @@ 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.model = OAuth2Model(
+ flows=cast(OAuthFlowsModel, flows), description=description
+ )
self.scheme_name = scheme_name or self.__class__.__name__
self.auto_error = auto_error
@@ -148,7 +150,9 @@ class OAuth2PasswordBearer(OAuth2):
):
if not scopes:
scopes = {}
- flows = OAuthFlowsModel(password={"tokenUrl": tokenUrl, "scopes": scopes})
+ flows = OAuthFlowsModel(
+ password=cast(Any, {"tokenUrl": tokenUrl, "scopes": scopes})
+ )
super().__init__(
flows=flows,
scheme_name=scheme_name,
@@ -185,12 +189,15 @@ class OAuth2AuthorizationCodeBearer(OAuth2):
if not scopes:
scopes = {}
flows = OAuthFlowsModel(
- authorizationCode={
- "authorizationUrl": authorizationUrl,
- "tokenUrl": tokenUrl,
- "refreshUrl": refreshUrl,
- "scopes": scopes,
- }
+ authorizationCode=cast(
+ Any,
+ {
+ "authorizationUrl": authorizationUrl,
+ "tokenUrl": tokenUrl,
+ "refreshUrl": refreshUrl,
+ "scopes": scopes,
+ },
+ )
)
super().__init__(
flows=flows,
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 391c47d81..9b9ebcb85 100644
--- a/fastapi/utils.py
+++ b/fastapi/utils.py
@@ -1,9 +1,19 @@
-import functools
import re
import warnings
from dataclasses import is_dataclass
from enum import Enum
-from typing import TYPE_CHECKING, Any, Dict, Optional, Set, Type, Union, cast
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ Dict,
+ MutableMapping,
+ Optional,
+ Set,
+ Type,
+ Union,
+ cast,
+)
+from weakref import WeakKeyDictionary
import fastapi
from fastapi.datastructures import DefaultPlaceholder, DefaultType
@@ -17,6 +27,11 @@ from pydantic.utils import lenient_issubclass
if TYPE_CHECKING: # pragma: nocover
from .routing import APIRoute
+# Cache for `create_cloned_field`
+_CLONED_TYPES_CACHE: MutableMapping[
+ Type[BaseModel], Type[BaseModel]
+] = WeakKeyDictionary()
+
def is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool:
if status_code is None:
@@ -73,19 +88,17 @@ 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(
"Invalid args for response field! Hint: "
@@ -101,11 +114,13 @@ def create_response_field(
def create_cloned_field(
field: ModelField,
*,
- cloned_types: Optional[Dict[Type[BaseModel], Type[BaseModel]]] = None,
+ cloned_types: Optional[MutableMapping[Type[BaseModel], Type[BaseModel]]] = None,
) -> ModelField:
- # _cloned_types has already cloned types, to support recursive models
+ # cloned_types caches already cloned types to support recursive models and improve
+ # performance by avoiding unecessary cloning
if cloned_types is None:
- cloned_types = {}
+ cloned_types = _CLONED_TYPES_CACHE
+
original_type = field.type_
if is_dataclass(original_type) and hasattr(original_type, "__pydantic_model__"):
original_type = original_type.__pydantic_model__
diff --git a/pyproject.toml b/pyproject.toml
index 7fb8078f9..547137144 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,8 +41,8 @@ classifiers = [
"Topic :: Internet :: WWW/HTTP",
]
dependencies = [
- "starlette==0.22.0",
- "pydantic >=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0",
+ "starlette>=0.27.0,<0.28.0",
+ "pydantic>=1.7.4,!=1.8,!=1.8.1,<2.0.0",
]
dynamic = ["version"]
@@ -49,48 +51,6 @@ Homepage = "https://github.com/tiangolo/fastapi"
Documentation = "https://fastapi.tiangolo.com/"
[project.optional-dependencies]
-test = [
- "pytest >=7.1.3,<8.0.0",
- "coverage[toml] >= 6.5.0,< 8.0",
- "mypy ==0.982",
- "ruff ==0.0.138",
- "black == 22.10.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.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",
- "flask >=1.1.2,<3.0.0",
- "anyio[trio] >=3.2.1,<4.0.0",
- "python-jose[cryptography] >=3.3.0,<4.0.0",
- "pyyaml >=5.3.1,<7.0.0",
- "passlib[bcrypt] >=1.7.2,<2.0.0",
-
- # types
- "types-ujson ==5.6.0.0",
- "types-orjson ==3.6.2",
-]
-doc = [
- "mkdocs >=1.1.2,<2.0.0",
- "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[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.21.0",
- "pre-commit >=2.17.0,<3.0.0",
-]
all = [
"httpx >=0.23.0",
"jinja2 >=2.11.2",
@@ -106,10 +66,6 @@ all = [
[tool.hatch.version]
path = "fastapi/__init__.py"
-[tool.isort]
-profile = "black"
-known_third_party = ["fastapi", "pydantic", "starlette"]
-
[tool.mypy]
strict = true
@@ -165,7 +121,7 @@ select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
- # "I", # isort
+ "I", # isort
"C", # flake8-comprehensions
"B", # flake8-bugbear
]
@@ -185,6 +141,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/requirements-docs.txt b/requirements-docs.txt
new file mode 100644
index 000000000..e9d0567ed
--- /dev/null
+++ b/requirements-docs.txt
@@ -0,0 +1,8 @@
+-e .
+mkdocs >=1.1.2,<2.0.0
+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
+typer-cli >=0.0.13,<0.0.14
+typer[all] >=0.6.1,<0.8.0
+pyyaml >=5.3.1,<7.0.0
diff --git a/requirements-tests.txt b/requirements-tests.txt
new file mode 100644
index 000000000..3ef3c4fd9
--- /dev/null
+++ b/requirements-tests.txt
@@ -0,0 +1,25 @@
+-e .
+pytest >=7.1.3,<8.0.0
+coverage[toml] >= 6.5.0,< 8.0
+mypy ==1.3.0
+ruff ==0.0.272
+black == 23.3.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.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.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
+pyyaml >=5.3.1,<7.0.0
+passlib[bcrypt] >=1.7.2,<2.0.0
+
+# types
+types-ujson ==5.7.0.1
+types-orjson ==3.6.2
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 000000000..cb9abb44a
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,5 @@
+-e .[all]
+-r requirements-tests.txt
+-r requirements-docs.txt
+uvicorn[standard] >=0.12.0,<0.21.0
+pre-commit >=2.17.0,<3.0.0
diff --git a/scripts/build-docs.sh b/scripts/build-docs.sh
index 383ad3f44..ebf864afa 100755
--- a/scripts/build-docs.sh
+++ b/scripts/build-docs.sh
@@ -3,4 +3,6 @@
set -e
set -x
+# Check README.md is up to date
+python ./scripts/docs.py verify-readme
python ./scripts/docs.py build-all
diff --git a/scripts/format.sh b/scripts/format.sh
index 3ac1fead8..3fb3eb4f1 100755
--- a/scripts/format.sh
+++ b/scripts/format.sh
@@ -3,4 +3,3 @@ set -x
ruff fastapi tests docs_src scripts --fix
black fastapi tests docs_src scripts
-isort fastapi tests docs_src scripts
diff --git a/scripts/lint.sh b/scripts/lint.sh
index 0feb973a8..4db5caa96 100755
--- a/scripts/lint.sh
+++ b/scripts/lint.sh
@@ -6,4 +6,3 @@ set -x
mypy fastapi
ruff fastapi tests docs_src scripts
black fastapi tests --check
-isort fastapi tests docs_src scripts --check-only
diff --git a/scripts/test.sh b/scripts/test.sh
index 62449ea41..7d17add8f 100755
--- a/scripts/test.sh
+++ b/scripts/test.sh
@@ -3,7 +3,5 @@
set -e
set -x
-# Check README.md is up to date
-python ./scripts/docs.py verify-readme
export PYTHONPATH=./docs_src
coverage run -m pytest tests ${@}
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_empty_router.py b/tests/test_empty_router.py
index 186ceb347..1a40cbe30 100644
--- a/tests/test_empty_router.py
+++ b/tests/test_empty_router.py
@@ -1,5 +1,6 @@
import pytest
from fastapi import APIRouter, FastAPI
+from fastapi.exceptions import FastAPIError
from fastapi.testclient import TestClient
app = FastAPI()
@@ -31,5 +32,5 @@ def test_use_empty():
def test_include_empty():
# if both include and router.path are empty - it should raise exception
- with pytest.raises(Exception):
+ with pytest.raises(FastAPIError):
app.include_router(router)
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 50ec753a0..14770fed0 100644
--- a/tests/test_reponse_set_reponse_code_empty.py
+++ b/tests/test_reponse_set_reponse_code_empty.py
@@ -22,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
index e45364149..7decdff7d 100644
--- a/tests/test_response_model_as_return_annotation.py
+++ b/tests/test_response_model_as_return_annotation.py
@@ -249,617 +249,9 @@ def no_response_model_annotation_json_response_class() -> JSONResponse:
return JSONResponse(content={"foo": "bar"})
-openapi_schema = {
- "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"},
- },
- },
- }
- },
-}
-
-
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_no_response_model_no_annotation_return_model():
response = client.get("/no_response_model-no_annotation-return_model")
assert response.status_code == 200, response.text
@@ -1109,3 +501,608 @@ def test_invalid_response_model_field():
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"