mirror of https://github.com/tiangolo/fastapi.git
358 lines
16 KiB
Markdown
358 lines
16 KiB
Markdown
# Modelo de resposta - Tipo de retorno
|
||
|
||
Você pode declarar o tipo usado para a resposta anotando o **tipo de retorno** *da função de operação de rota*.
|
||
|
||
Você pode usar **anotações de tipo** da mesma forma que usaria para dados de entrada em **parâmetros** de função, você pode usar modelos Pydantic, listas, dicionários, valores escalares como inteiros, booleanos, etc.
|
||
|
||
{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}
|
||
|
||
O FastAPI usará este tipo de retorno para:
|
||
|
||
* **Validar** os dados retornados.
|
||
* Se os dados forem inválidos (por exemplo, se estiver faltando um campo), significa que o código do *seu* aplicativo está quebrado, não retornando o que deveria, e retornará um erro de servidor em vez de retornar dados incorretos. Dessa forma, você e seus clientes podem ter certeza de que receberão os dados e o formato de dados esperados.
|
||
* Adicionar um **Esquema JSON** para a resposta, na *operação de rota* do OpenAPI.
|
||
* Isso será usado pela **documentação automática**.
|
||
* Também será usado por ferramentas de geração automática de código do cliente.
|
||
|
||
Mas o mais importante:
|
||
|
||
* Ele **limitará e filtrará** os dados de saída para o que está definido no tipo de retorno.
|
||
* Isso é particularmente importante para a **segurança**, veremos mais sobre isso abaixo.
|
||
|
||
## Parâmetro `response_model`
|
||
|
||
Existem alguns casos em que você precisa ou deseja retornar alguns dados que não são exatamente o que o tipo declara.
|
||
|
||
Por exemplo, você pode querer **retornar um dicionário** ou um objeto de banco de dados, mas **declará-lo como um modelo Pydantic**. Dessa forma, o modelo Pydantic faria toda a documentação de dados, validação, etc. para o objeto que você retornou (por exemplo, um dicionário ou objeto de banco de dados).
|
||
|
||
Se você adicionasse a anotação do tipo de retorno, ferramentas e editores reclamariam com um erro (correto) informando que sua função está retornando um tipo (por exemplo, um dict) diferente do que você declarou (por exemplo, um modelo Pydantic).
|
||
|
||
Nesses casos, você pode usar o parâmetro `response_model` do *decorador de operação de rota* em vez do tipo de retorno.
|
||
|
||
Você pode usar o parâmetro `response_model` em qualquer uma das *operações de rota*:
|
||
|
||
* `@app.get()`
|
||
* `@app.post()`
|
||
* `@app.put()`
|
||
* `@app.delete()`
|
||
* etc.
|
||
|
||
{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}
|
||
|
||
/// note | Nota
|
||
|
||
Observe que `response_model` é um parâmetro do método "decorator" (`get`, `post`, etc). Não da sua *função de operação de rota*, como todos os parâmetros e corpo.
|
||
|
||
///
|
||
|
||
`response_model` recebe o mesmo tipo que você declararia para um campo de modelo Pydantic, então, pode ser um modelo Pydantic, mas também pode ser, por exemplo, uma `lista` de modelos Pydantic, como `List[Item]`.
|
||
|
||
O FastAPI usará este `response_model` para fazer toda a documentação de dados, validação, etc. e também para **converter e filtrar os dados de saída** para sua declaração de tipo.
|
||
|
||
/// tip | Dica
|
||
|
||
Se você tiver verificações de tipo rigorosas em seu editor, mypy, etc, você pode declarar o tipo de retorno da função como `Any`.
|
||
|
||
Dessa forma, você diz ao editor que está retornando qualquer coisa intencionalmente. Mas o FastAPI ainda fará a documentação de dados, validação, filtragem, etc. com o `response_model`.
|
||
|
||
///
|
||
|
||
### Prioridade `response_model`
|
||
|
||
Se você declarar tanto um tipo de retorno quanto um `response_model`, o `response_model` terá prioridade e será usado pelo FastAPI.
|
||
|
||
Dessa forma, você pode adicionar anotações de tipo corretas às suas funções, mesmo quando estiver retornando um tipo diferente do modelo de resposta, para ser usado pelo editor e ferramentas como mypy. E ainda assim você pode fazer com que o FastAPI faça a validação de dados, documentação, etc. usando o `response_model`.
|
||
|
||
Você também pode usar `response_model=None` para desabilitar a criação de um modelo de resposta para essa *operação de rota*, você pode precisar fazer isso se estiver adicionando anotações de tipo para coisas que não são campos Pydantic válidos, você verá um exemplo disso em uma das seções abaixo.
|
||
|
||
## Retorna os mesmos dados de entrada
|
||
|
||
Aqui estamos declarando um modelo `UserIn`, ele conterá uma senha em texto simples:
|
||
|
||
{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}
|
||
|
||
/// info | Informação
|
||
|
||
Para usar `EmailStr`, primeiro instale <a href="https://github.com/JoshData/python-email-validator" class="external-link" target="_blank">`email-validator`</a>.
|
||
|
||
Certifique-se de criar um [ambiente virtual](../virtual-environments.md){.internal-link target=_blank}, ative-o e instale-o, por exemplo:
|
||
|
||
```console
|
||
$ pip install email-validator
|
||
```
|
||
|
||
ou com:
|
||
|
||
```console
|
||
$ pip install "pydantic[email]"
|
||
```
|
||
|
||
///
|
||
|
||
E estamos usando este modelo para declarar nossa entrada e o mesmo modelo para declarar nossa saída:
|
||
|
||
{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}
|
||
|
||
Agora, sempre que um navegador estiver criando um usuário com uma senha, a API retornará a mesma senha na resposta.
|
||
|
||
Neste caso, pode não ser um problema, porque é o mesmo usuário enviando a senha.
|
||
|
||
Mas se usarmos o mesmo modelo para outra *operação de rota*, poderíamos estar enviando as senhas dos nossos usuários para todos os clientes.
|
||
|
||
/// danger | Perigo
|
||
|
||
Nunca armazene a senha simples de um usuário ou envie-a em uma resposta como esta, a menos que você saiba todas as ressalvas e saiba o que está fazendo.
|
||
|
||
///
|
||
|
||
## Adicionar um modelo de saída
|
||
|
||
Podemos, em vez disso, criar um modelo de entrada com a senha em texto simples e um modelo de saída sem ela:
|
||
|
||
{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}
|
||
|
||
Aqui, embora nossa *função de operação de rota* esteja retornando o mesmo usuário de entrada que contém a senha:
|
||
|
||
{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}
|
||
|
||
...declaramos o `response_model` como nosso modelo `UserOut`, que não inclui a senha:
|
||
|
||
{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}
|
||
|
||
Então, **FastAPI** cuidará de filtrar todos os dados que não são declarados no modelo de saída (usando Pydantic).
|
||
|
||
### `response_model` ou Tipo de Retorno
|
||
|
||
Neste caso, como os dois modelos são diferentes, se anotássemos o tipo de retorno da função como `UserOut`, o editor e as ferramentas reclamariam que estamos retornando um tipo inválido, pois são classes diferentes.
|
||
|
||
É por isso que neste exemplo temos que declará-lo no parâmetro `response_model`.
|
||
|
||
...mas continue lendo abaixo para ver como superar isso.
|
||
|
||
## Tipo de Retorno e Filtragem de Dados
|
||
|
||
Vamos continuar do exemplo anterior. Queríamos **anotar a função com um tipo**, mas queríamos poder retornar da função algo que realmente incluísse **mais dados**.
|
||
|
||
Queremos que o FastAPI continue **filtrando** os dados usando o modelo de resposta. Para que, embora a função retorne mais dados, a resposta inclua apenas os campos declarados no modelo de resposta.
|
||
|
||
No exemplo anterior, como as classes eram diferentes, tivemos que usar o parâmetro `response_model`. Mas isso também significa que não temos suporte do editor e das ferramentas verificando o tipo de retorno da função.
|
||
|
||
Mas na maioria dos casos em que precisamos fazer algo assim, queremos que o modelo apenas **filtre/remova** alguns dados como neste exemplo.
|
||
|
||
E nesses casos, podemos usar classes e herança para aproveitar as **anotações de tipo** de função para obter melhor suporte no editor e nas ferramentas, e ainda obter a **filtragem de dados** FastAPI.
|
||
|
||
{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}
|
||
|
||
Com isso, temos suporte de ferramentas, de editores e mypy, pois este código está correto em termos de tipos, mas também obtemos a filtragem de dados do FastAPI.
|
||
|
||
Como isso funciona? Vamos verificar. 🤓
|
||
|
||
### Anotações de tipo e ferramentas
|
||
|
||
Primeiro, vamos ver como editores, mypy e outras ferramentas veriam isso.
|
||
|
||
`BaseUser` tem os campos base. Então `UserIn` herda de `BaseUser` e adiciona o campo `password`, então, ele incluirá todos os campos de ambos os modelos.
|
||
|
||
Anotamos o tipo de retorno da função como `BaseUser`, mas na verdade estamos retornando uma instância `UserIn`.
|
||
|
||
O editor, mypy e outras ferramentas não reclamarão disso porque, em termos de digitação, `UserIn` é uma subclasse de `BaseUser`, o que significa que é um tipo *válido* quando o que é esperado é qualquer coisa que seja um `BaseUser`.
|
||
|
||
### Filtragem de dados FastAPI
|
||
|
||
Agora, para FastAPI, ele verá o tipo de retorno e garantirá que o que você retornar inclua **apenas** os campos que são declarados no tipo.
|
||
|
||
O FastAPI faz várias coisas internamente com o Pydantic para garantir que essas mesmas regras de herança de classe não sejam usadas para a filtragem de dados retornados, caso contrário, você pode acabar retornando muito mais dados do que o esperado.
|
||
|
||
Dessa forma, você pode obter o melhor dos dois mundos: anotações de tipo com **suporte a ferramentas** e **filtragem de dados**.
|
||
|
||
## Veja na documentação
|
||
|
||
Quando você vê a documentação automática, pode verificar se o modelo de entrada e o modelo de saída terão seus próprios esquemas JSON:
|
||
|
||
<img src="/img/tutorial/response-model/image01.png">
|
||
|
||
E ambos os modelos serão usados para a documentação interativa da API:
|
||
|
||
<img src="/img/tutorial/response-model/image02.png">
|
||
|
||
## Outras anotações de tipo de retorno
|
||
|
||
Pode haver casos em que você retorna algo que não é um campo Pydantic válido e anota na função, apenas para obter o suporte fornecido pelas ferramentas (o editor, mypy, etc).
|
||
|
||
### Retornar uma resposta diretamente
|
||
|
||
O caso mais comum seria [retornar uma resposta diretamente, conforme explicado posteriormente na documentação avançada](../advanced/response-directly.md){.internal-link target=_blank}.
|
||
|
||
{* ../../docs_src/response_model/tutorial003_02.py hl[8,10:11] *}
|
||
|
||
Este caso simples é tratado automaticamente pelo FastAPI porque a anotação do tipo de retorno é a classe (ou uma subclasse de) `Response`.
|
||
|
||
E as ferramentas também ficarão felizes porque `RedirectResponse` e `JSONResponse` são subclasses de `Response`, então a anotação de tipo está correta.
|
||
|
||
### Anotar uma subclasse de resposta
|
||
|
||
Você também pode usar uma subclasse de `Response` na anotação de tipo:
|
||
|
||
{* ../../docs_src/response_model/tutorial003_03.py hl[8:9] *}
|
||
|
||
Isso também funcionará porque `RedirectResponse` é uma subclasse de `Response`, e o FastAPI tratará automaticamente este caso simples.
|
||
|
||
### Anotações de Tipo de Retorno Inválido
|
||
|
||
Mas quando você retorna algum outro objeto arbitrário que não é um tipo Pydantic válido (por exemplo, um objeto de banco de dados) e você o anota dessa forma na função, o FastAPI tentará criar um modelo de resposta Pydantic a partir dessa anotação de tipo e falhará.
|
||
|
||
O mesmo aconteceria se você tivesse algo como uma <abbr title='Uma união entre vários tipos significa "qualquer um desses tipos".'>união</abbr> entre tipos diferentes onde um ou mais deles não são tipos Pydantic válidos, por exemplo, isso falharia 💥:
|
||
|
||
{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}
|
||
|
||
... isso falha porque a anotação de tipo não é um tipo Pydantic e não é apenas uma única classe ou subclasse `Response`, é uma união (qualquer uma das duas) entre um `Response` e um `dict`.
|
||
|
||
### Desabilitar modelo de resposta
|
||
|
||
Continuando com o exemplo acima, você pode não querer ter a validação de dados padrão, documentação, filtragem, etc. que é realizada pelo FastAPI.
|
||
|
||
Mas você pode querer manter a anotação do tipo de retorno na função para obter o suporte de ferramentas como editores e verificadores de tipo (por exemplo, mypy).
|
||
|
||
Neste caso, você pode desabilitar a geração do modelo de resposta definindo `response_model=None`:
|
||
|
||
{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}
|
||
|
||
Isso fará com que o FastAPI pule a geração do modelo de resposta e, dessa forma, você pode ter quaisquer anotações de tipo de retorno que precisar sem afetar seu aplicativo FastAPI. 🤓
|
||
|
||
## Parâmetros de codificação do modelo de resposta
|
||
|
||
Seu modelo de resposta pode ter valores padrão, como:
|
||
|
||
{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}
|
||
|
||
* `description: Union[str, None] = None` (ou `str | None = None` no Python 3.10) tem um padrão de `None`.
|
||
* `tax: float = 10.5` tem um padrão de `10.5`.
|
||
* `tags: List[str] = []` tem um padrão de uma lista vazia: `[]`.
|
||
|
||
mas você pode querer omiti-los do resultado se eles não foram realmente armazenados.
|
||
|
||
Por exemplo, se você tem modelos com muitos atributos opcionais em um banco de dados NoSQL, mas não quer enviar respostas JSON muito longas cheias de valores padrão.
|
||
|
||
### Usar o parâmetro `response_model_exclude_unset`
|
||
|
||
Você pode definir o parâmetro `response_model_exclude_unset=True` do *decorador de operação de rota* :
|
||
|
||
{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}
|
||
|
||
e esses valores padrão não serão incluídos na resposta, apenas os valores realmente definidos.
|
||
|
||
Então, se você enviar uma solicitação para essa *operação de rota* para o item com ID `foo`, a resposta (sem incluir valores padrão) será:
|
||
|
||
```JSON
|
||
{
|
||
"name": "Foo",
|
||
"price": 50.2
|
||
}
|
||
```
|
||
|
||
/// info | Informação
|
||
|
||
No Pydantic v1, o método era chamado `.dict()`, ele foi descontinuado (mas ainda suportado) no Pydantic v2 e renomeado para `.model_dump()`.
|
||
|
||
Os exemplos aqui usam `.dict()` para compatibilidade com Pydantic v1, mas você deve usar `.model_dump()` em vez disso se puder usar Pydantic v2.
|
||
|
||
///
|
||
|
||
/// info | Informação
|
||
|
||
O FastAPI usa `.dict()` do modelo Pydantic com <a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">seu parâmetro `exclude_unset`</a> para chegar a isso.
|
||
|
||
///
|
||
|
||
/// info | Informação
|
||
|
||
Você também pode usar:
|
||
|
||
* `response_model_exclude_defaults=True`
|
||
* `response_model_exclude_none=True`
|
||
|
||
conforme descrito na <a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">documentação do Pydantic</a> para `exclude_defaults` e `exclude_none`.
|
||
|
||
///
|
||
|
||
#### Dados com valores para campos com padrões
|
||
|
||
Mas se seus dados tiverem valores para os campos do modelo com valores padrões, como o item com ID `bar`:
|
||
|
||
```Python hl_lines="3 5"
|
||
{
|
||
"name": "Bar",
|
||
"description": "The bartenders",
|
||
"price": 62,
|
||
"tax": 20.2
|
||
}
|
||
```
|
||
|
||
eles serão incluídos na resposta.
|
||
|
||
#### Dados com os mesmos valores que os padrões
|
||
|
||
Se os dados tiverem os mesmos valores que os padrões, como o item com ID `baz`:
|
||
|
||
```Python hl_lines="3 5-6"
|
||
{
|
||
"name": "Baz",
|
||
"description": None,
|
||
"price": 50.2,
|
||
"tax": 10.5,
|
||
"tags": []
|
||
}
|
||
```
|
||
|
||
O FastAPI é inteligente o suficiente (na verdade, o Pydantic é inteligente o suficiente) para perceber que, embora `description`, `tax` e `tags` tenham os mesmos valores que os padrões, eles foram definidos explicitamente (em vez de retirados dos padrões).
|
||
|
||
Portanto, eles serão incluídos na resposta JSON.
|
||
|
||
/// tip | Dica
|
||
|
||
Observe que os valores padrão podem ser qualquer coisa, não apenas `None`.
|
||
|
||
Eles podem ser uma lista (`[]`), um `float` de `10.5`, etc.
|
||
|
||
///
|
||
|
||
### `response_model_include` e `response_model_exclude`
|
||
|
||
Você também pode usar os parâmetros `response_model_include` e `response_model_exclude` do *decorador de operação de rota*.
|
||
|
||
Eles pegam um `set` de `str` com o nome dos atributos para incluir (omitindo o resto) ou para excluir (incluindo o resto).
|
||
|
||
Isso pode ser usado como um atalho rápido se você tiver apenas um modelo Pydantic e quiser remover alguns dados da saída.
|
||
|
||
/// tip | Dica
|
||
|
||
Mas ainda é recomendado usar as ideias acima, usando várias classes, em vez desses parâmetros.
|
||
|
||
Isso ocorre porque o Schema JSON gerado no OpenAPI do seu aplicativo (e a documentação) ainda será o único para o modelo completo, mesmo que você use `response_model_include` ou `response_model_exclude` para omitir alguns atributos.
|
||
|
||
Isso também se aplica ao `response_model_by_alias` que funciona de forma semelhante.
|
||
|
||
///
|
||
|
||
{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}
|
||
|
||
/// tip | Dica
|
||
|
||
A sintaxe `{"nome", "descrição"}` cria um `conjunto` com esses dois valores.
|
||
|
||
É equivalente a `set(["nome", "descrição"])`.
|
||
|
||
///
|
||
|
||
#### Usando `list`s em vez de `set`s
|
||
|
||
Se você esquecer de usar um `set` e usar uma `lista` ou `tupla` em vez disso, o FastAPI ainda o converterá em um `set` e funcionará corretamente:
|
||
|
||
{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}
|
||
|
||
## Recapitulação
|
||
|
||
Use o parâmetro `response_model` do *decorador de operação de rota* para definir modelos de resposta e, especialmente, para garantir que dados privados sejam filtrados.
|
||
|
||
Use `response_model_exclude_unset` para retornar apenas os valores definidos explicitamente.
|