committed by
GitHub
4 changed files with 319 additions and 0 deletions
@ -0,0 +1,101 @@ |
|||||
|
# Usando Dataclasses |
||||
|
|
||||
|
FastAPI é construído em cima do **Pydantic**, e eu tenho mostrado como usar modelos Pydantic para declarar requisições e respostas. |
||||
|
|
||||
|
Mas o FastAPI também suporta o uso de <a href="https://docs.python.org/3/library/dataclasses.html" class="external-link" target="_blank">`dataclasses`</a> da mesma forma: |
||||
|
|
||||
|
```Python hl_lines="1 7-12 19-20" |
||||
|
{!../../docs_src/dataclasses/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
Isso ainda é suportado graças ao **Pydantic**, pois ele tem <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel" class="external-link" target="_blank">suporte interno para `dataclasses`</a>. |
||||
|
|
||||
|
Então, mesmo com o código acima que não usa Pydantic explicitamente, o FastAPI está usando Pydantic para converter essas dataclasses padrão para a versão do Pydantic. |
||||
|
|
||||
|
E claro, ele suporta o mesmo: |
||||
|
|
||||
|
* validação de dados |
||||
|
* serialização de dados |
||||
|
* documentação de dados, etc. |
||||
|
|
||||
|
Isso funciona da mesma forma que com os modelos Pydantic. E na verdade é alcançado da mesma maneira por baixo dos panos, usando Pydantic. |
||||
|
|
||||
|
/// info | Informação |
||||
|
|
||||
|
Lembre-se de que dataclasses não podem fazer tudo o que os modelos Pydantic podem fazer. |
||||
|
|
||||
|
Então, você ainda pode precisar usar modelos Pydantic. |
||||
|
|
||||
|
Mas se você tem um monte de dataclasses por aí, este é um truque legal para usá-las para alimentar uma API web usando FastAPI. 🤓 |
||||
|
|
||||
|
/// |
||||
|
|
||||
|
## Dataclasses em `response_model` |
||||
|
|
||||
|
Você também pode usar `dataclasses` no parâmetro `response_model`: |
||||
|
|
||||
|
```Python hl_lines="1 7-13 19" |
||||
|
{!../../docs_src/dataclasses/tutorial002.py!} |
||||
|
``` |
||||
|
|
||||
|
A dataclass será automaticamente convertida para uma dataclass Pydantic. |
||||
|
|
||||
|
Dessa forma, seu esquema aparecerá na interface de documentação da API: |
||||
|
|
||||
|
<img src="/img/tutorial/dataclasses/image01.png"> |
||||
|
|
||||
|
## Dataclasses em Estruturas de Dados Aninhadas |
||||
|
|
||||
|
Você também pode combinar `dataclasses` com outras anotações de tipo para criar estruturas de dados aninhadas. |
||||
|
|
||||
|
Em alguns casos, você ainda pode ter que usar a versão do Pydantic das `dataclasses`. Por exemplo, se você tiver erros com a documentação da API gerada automaticamente. |
||||
|
|
||||
|
Nesse caso, você pode simplesmente trocar as `dataclasses` padrão por `pydantic.dataclasses`, que é um substituto direto: |
||||
|
|
||||
|
```{ .python .annotate hl_lines="1 5 8-11 14-17 23-25 28" } |
||||
|
{!../../docs_src/dataclasses/tutorial003.py!} |
||||
|
``` |
||||
|
|
||||
|
1. Ainda importamos `field` das `dataclasses` padrão. |
||||
|
|
||||
|
2. `pydantic.dataclasses` é um substituto direto para `dataclasses`. |
||||
|
|
||||
|
3. A dataclass `Author` inclui uma lista de dataclasses `Item`. |
||||
|
|
||||
|
4. A dataclass `Author` é usada como o parâmetro `response_model`. |
||||
|
|
||||
|
5. Você pode usar outras anotações de tipo padrão com dataclasses como o corpo da requisição. |
||||
|
|
||||
|
Neste caso, é uma lista de dataclasses `Item`. |
||||
|
|
||||
|
6. Aqui estamos retornando um dicionário que contém `items`, que é uma lista de dataclasses. |
||||
|
|
||||
|
O FastAPI ainda é capaz de <abbr title="converter os dados para um formato que pode ser transmitido">serializar</abbr> os dados para JSON. |
||||
|
|
||||
|
7. Aqui o `response_model` está usando uma anotação de tipo de uma lista de dataclasses `Author`. |
||||
|
|
||||
|
Novamente, você pode combinar `dataclasses` com anotações de tipo padrão. |
||||
|
|
||||
|
8. Note que esta *função de operação de rota* usa `def` regular em vez de `async def`. |
||||
|
|
||||
|
Como sempre, no FastAPI você pode combinar `def` e `async def` conforme necessário. |
||||
|
|
||||
|
Se você precisar de uma atualização sobre quando usar qual, confira a seção _"Com pressa?"_ na documentação sobre [`async` e `await`](../async.md#in-a-hurry){.internal-link target=_blank}. |
||||
|
|
||||
|
9. Esta *função de operação de rota* não está retornando dataclasses (embora pudesse), mas uma lista de dicionários com dados internos. |
||||
|
|
||||
|
O FastAPI usará o parâmetro `response_model` (que inclui dataclasses) para converter a resposta. |
||||
|
|
||||
|
Você pode combinar `dataclasses` com outras anotações de tipo em muitas combinações diferentes para formar estruturas de dados complexas. |
||||
|
|
||||
|
Confira as dicas de anotação no código acima para ver mais detalhes específicos. |
||||
|
|
||||
|
## Saiba Mais |
||||
|
|
||||
|
Você também pode combinar `dataclasses` com outros modelos Pydantic, herdar deles, incluí-los em seus próprios modelos, etc. |
||||
|
|
||||
|
Para saber mais, confira a <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/" class="external-link" target="_blank">documentação do Pydantic sobre dataclasses</a>. |
||||
|
|
||||
|
## Versão |
||||
|
|
||||
|
Isso está disponível desde a versão `0.67.0` do FastAPI. 🔖 |
@ -0,0 +1,121 @@ |
|||||
|
# Requisições Personalizadas e Classes da APIRoute |
||||
|
|
||||
|
Em algum casos, você pode querer sobreescrever a lógica usada pelas classes `Request`e `APIRoute`. |
||||
|
|
||||
|
Em particular, isso pode ser uma boa alternativa para uma lógica em um middleware |
||||
|
|
||||
|
Por exemplo, se você quiser ler ou manipular o corpo da requisição antes que ele seja processado pela sua aplicação. |
||||
|
|
||||
|
/// danger | Perigo |
||||
|
|
||||
|
Isso é um recurso "avançado". |
||||
|
|
||||
|
Se você for um iniciante em **FastAPI** você deve considerar pular essa seção. |
||||
|
|
||||
|
/// |
||||
|
|
||||
|
## Casos de Uso |
||||
|
|
||||
|
Alguns casos de uso incluem: |
||||
|
|
||||
|
* Converter requisições não-JSON para JSON (por exemplo, <a href="https://msgpack.org/index.html" class="external-link" target="_blank">`msgpack`</a>). |
||||
|
* Descomprimir corpos de requisição comprimidos com gzip. |
||||
|
* Registrar automaticamente todos os corpos de requisição. |
||||
|
|
||||
|
## Manipulando codificações de corpo de requisição personalizadas |
||||
|
|
||||
|
Vamos ver como usar uma subclasse personalizada de `Request` para descomprimir requisições gzip. |
||||
|
|
||||
|
E uma subclasse de `APIRoute` para usar essa classe de requisição personalizada. |
||||
|
|
||||
|
### Criar uma classe `GzipRequest` personalizada |
||||
|
|
||||
|
/// tip | Dica |
||||
|
|
||||
|
Isso é um exemplo de brincadeira para demonstrar como funciona, se você precisar de suporte para Gzip, você pode usar o [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware){.internal-link target=_blank} fornecido. |
||||
|
|
||||
|
/// |
||||
|
|
||||
|
Primeiro, criamos uma classe `GzipRequest`, que irá sobrescrever o método `Request.body()` para descomprimir o corpo na presença de um cabeçalho apropriado. |
||||
|
|
||||
|
Se não houver `gzip` no cabeçalho, ele não tentará descomprimir o corpo. |
||||
|
|
||||
|
Dessa forma, a mesma classe de rota pode lidar com requisições comprimidas ou não comprimidas. |
||||
|
|
||||
|
```Python hl_lines="8-15" |
||||
|
{!../../docs_src/custom_request_and_route/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### Criar uma classe `GzipRoute` personalizada |
||||
|
|
||||
|
Em seguida, criamos uma subclasse personalizada de `fastapi.routing.APIRoute` que fará uso do `GzipRequest`. |
||||
|
|
||||
|
Dessa vez, ele irá sobrescrever o método `APIRoute.get_route_handler()`. |
||||
|
|
||||
|
Esse método retorna uma função. E essa função é o que irá receber uma requisição e retornar uma resposta. |
||||
|
|
||||
|
Aqui nós usamos para criar um `GzipRequest` a partir da requisição original. |
||||
|
|
||||
|
```Python hl_lines="18-26" |
||||
|
{!../../docs_src/custom_request_and_route/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
/// note | Detalhes Técnicos |
||||
|
|
||||
|
Um `Request` também tem um `request.receive`, que é uma função para "receber" o corpo da requisição. |
||||
|
|
||||
|
Um `Request` também tem um `request.receive`, que é uma função para "receber" o corpo da requisição. |
||||
|
|
||||
|
O dicionário `scope` e a função `receive` são ambos parte da especificação ASGI. |
||||
|
|
||||
|
E essas duas coisas, `scope` e `receive`, são o que é necessário para criar uma nova instância de `Request`. |
||||
|
|
||||
|
Para aprender mais sobre o `Request` confira a <a href="https://www.starlette.io/requests/" class="external-link" target="_blank">documentação do Starlette sobre Requests</a>. |
||||
|
|
||||
|
/// |
||||
|
|
||||
|
A única coisa que a função retornada por `GzipRequest.get_route_handler` faz de diferente é converter o `Request` para um `GzipRequest`. |
||||
|
|
||||
|
Fazendo isso, nosso `GzipRequest` irá cuidar de descomprimir os dados (se necessário) antes de passá-los para nossas *operações de rota*. |
||||
|
|
||||
|
Depois disso, toda a lógica de processamento é a mesma. |
||||
|
|
||||
|
Mas por causa das nossas mudanças em `GzipRequest.body`, o corpo da requisição será automaticamente descomprimido quando for carregado pelo **FastAPI** quando necessário. |
||||
|
|
||||
|
## Acessando o corpo da requisição em um manipulador de exceção |
||||
|
|
||||
|
/// tip | Dica |
||||
|
|
||||
|
Para resolver esse mesmo problema, é provavelmente muito mais fácil usar o `body` em um manipulador personalizado para `RequestValidationError` ([Tratando Erros](../tutorial/handling-errors.md#use-the-requestvalidationerror-body){.internal-link target=_blank}). |
||||
|
|
||||
|
Mas esse exemplo ainda é valido e mostra como interagir com os componentes internos. |
||||
|
|
||||
|
/// |
||||
|
|
||||
|
Também podemos usar essa mesma abordagem para acessar o corpo da requisição em um manipulador de exceção. |
||||
|
|
||||
|
Tudo que precisamos fazer é manipular a requisição dentro de um bloco `try`/`except`: |
||||
|
|
||||
|
```Python hl_lines="13 15" |
||||
|
{!../../docs_src/custom_request_and_route/tutorial002.py!} |
||||
|
``` |
||||
|
|
||||
|
Se uma exceção ocorrer, a instância `Request` ainda estará em escopo, então podemos ler e fazer uso do corpo da requisição ao lidar com o erro: |
||||
|
|
||||
|
```Python hl_lines="16-18" |
||||
|
{!../../docs_src/custom_request_and_route/tutorial002.py!} |
||||
|
``` |
||||
|
|
||||
|
## Classe `APIRoute` personalizada em um router |
||||
|
|
||||
|
você também pode definir o parametro `route_class` de uma `APIRouter`; |
||||
|
|
||||
|
```Python hl_lines="26" |
||||
|
{!../../docs_src/custom_request_and_route/tutorial003.py!} |
||||
|
``` |
||||
|
|
||||
|
Nesse exemplo, as *operações de rota* sob o `router` irão usar a classe `TimedRoute` personalizada, e terão um cabeçalho extra `X-Response-Time` na resposta com o tempo que levou para gerar a resposta: |
||||
|
|
||||
|
```Python hl_lines="13-20" |
||||
|
{!../../docs_src/custom_request_and_route/tutorial003.py!} |
||||
|
``` |
@ -0,0 +1,91 @@ |
|||||
|
|
||||
|
# Extendendo o OpenAPI |
||||
|
|
||||
|
Existem alguns casos em que pode ser necessário modificar o esquema OpenAPI gerado. |
||||
|
|
||||
|
Nesta seção, você verá como fazer isso. |
||||
|
|
||||
|
## O processo normal |
||||
|
|
||||
|
O processo normal (padrão) é o seguinte: |
||||
|
|
||||
|
Uma aplicação (instância) do `FastAPI` possui um método `.openapi()` que deve retornar o esquema OpenAPI. |
||||
|
|
||||
|
Como parte da criação do objeto de aplicação, uma *operação de rota* para `/openapi.json` (ou para o que você definir como `openapi_url`) é registrada. |
||||
|
|
||||
|
Ela apenas retorna uma resposta JSON com o resultado do método `.openapi()` da aplicação. |
||||
|
|
||||
|
Por padrão, o que o método `.openapi()` faz é verificar se a propriedade `.openapi_schema` tem conteúdo e retorná-lo. |
||||
|
|
||||
|
Se não tiver, ele gera o conteúdo usando a função utilitária em `fastapi.openapi.utils.get_openapi`. |
||||
|
|
||||
|
E essa função `get_openapi()` recebe como parâmetros: |
||||
|
|
||||
|
* `title`: O título do OpenAPI, exibido na documentação. |
||||
|
* `version`: A versão da sua API, por exemplo, `2.5.0`. |
||||
|
* `openapi_version`: A versão da especificação OpenAPI utilizada. Por padrão, a mais recente: `3.1.0`. |
||||
|
* `summary`: Um resumo curto da API. |
||||
|
* `description`: A descrição da sua API, que pode incluir markdown e será exibida na documentação. |
||||
|
* `routes`: Uma lista de rotas, que são cada uma das *operações de rota* registradas. Elas são obtidas de `app.routes`. |
||||
|
|
||||
|
/// info | Informação |
||||
|
|
||||
|
O parâmetro `summary` está disponível no OpenAPI 3.1.0 e superior, suportado pelo FastAPI 0.99.0 e superior. |
||||
|
|
||||
|
/// |
||||
|
|
||||
|
## Sobrescrevendo os padrões |
||||
|
|
||||
|
Com as informações acima, você pode usar a mesma função utilitária para gerar o esquema OpenAPI e sobrescrever cada parte que precisar. |
||||
|
|
||||
|
Por exemplo, vamos adicionar <a href="https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo" class="external-link" target="_blank">Extensão OpenAPI do ReDoc para incluir um logo personalizado</a>. |
||||
|
|
||||
|
### **FastAPI** Normal |
||||
|
|
||||
|
Primeiro, escreva toda a sua aplicação **FastAPI** normalmente: |
||||
|
|
||||
|
```Python hl_lines="1 4 7-9" |
||||
|
{!../../docs_src/extending_openapi/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### Gerar o esquema OpenAPI |
||||
|
|
||||
|
Em seguida, use a mesma função utilitária para gerar o esquema OpenAPI, dentro de uma função `custom_openapi()`: |
||||
|
|
||||
|
```Python hl_lines="2 15-21" |
||||
|
{!../../docs_src/extending_openapi/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### Modificar o esquema OpenAPI |
||||
|
|
||||
|
Agora, você pode adicionar a extensão do ReDoc, incluindo um `x-logo` personalizado ao "objeto" `info` no esquema OpenAPI: |
||||
|
|
||||
|
```Python hl_lines="22-24" |
||||
|
{!../../docs_src/extending_openapi/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### Armazenar em cache o esquema OpenAPI |
||||
|
|
||||
|
Você pode usar a propriedade `.openapi_schema` como um "cache" para armazenar o esquema gerado. |
||||
|
|
||||
|
Dessa forma, sua aplicação não precisará gerar o esquema toda vez que um usuário abrir a documentação da sua API. |
||||
|
|
||||
|
Ele será gerado apenas uma vez, e o mesmo esquema armazenado em cache será utilizado nas próximas requisições. |
||||
|
|
||||
|
```Python hl_lines="13-14 25-26" |
||||
|
{!../../docs_src/extending_openapi/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### Sobrescrever o método |
||||
|
|
||||
|
Agora, você pode substituir o método `.openapi()` pela sua nova função. |
||||
|
|
||||
|
```Python hl_lines="29" |
||||
|
{!../../docs_src/extending_openapi/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
### Verificar |
||||
|
|
||||
|
Uma vez que você acessar <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>, verá que está usando seu logo personalizado (neste exemplo, o logo do **FastAPI**): |
||||
|
|
||||
|
<img src="/docs/en/docs/img/tutorial/extending-openapi/image01.png"> |
Loading…
Reference in new issue