Sync fastapi docs from 7cb06f36 on 2026-07-11
This commit is contained in:
@@ -11,7 +11,7 @@ Use da seguinte forma:
|
||||
* Verifique se está tudo certo na tradução.
|
||||
* Se necessário, melhore seu prompt específico do idioma, o prompt geral ou o documento em inglês.
|
||||
* Em seguida, corrija manualmente os problemas restantes na tradução, para que fique uma boa tradução.
|
||||
* Retraduzir, tendo a boa tradução no lugar. O resultado ideal seria que o LLM não fizesse mais mudanças na tradução. Isso significa que o prompt geral e o seu prompt específico do idioma estão tão bons quanto possível (às vezes fará algumas mudanças aparentemente aleatórias, a razão é que [LLMs não são algoritmos determinísticos](https://doublespeak.chat/#/handbook#deterministic-output)).
|
||||
* Retraduza, tendo a boa tradução no lugar. O resultado ideal seria que o LLM não fizesse mais mudanças na tradução. Isso significa que o prompt geral e o seu prompt específico do idioma estão tão bons quanto possível (às vezes fará algumas mudanças aparentemente aleatórias, a razão é que [LLMs não são algoritmos determinísticos](https://doublespeak.chat/#/handbook#deterministic-output)).
|
||||
|
||||
Os testes:
|
||||
|
||||
@@ -189,15 +189,15 @@ Aqui estão algumas coisas envolvidas em elementos HTML "abbr" (algumas são inv
|
||||
|
||||
### O abbr fornece uma frase completa { #the-abbr-gives-a-full-phrase }
|
||||
|
||||
* <abbr title="Getting Things Done – Fazer as Coisas">GTD</abbr>
|
||||
* <abbr title="less than – menos que"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token – Token Web XML">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface – Interface de Gateway de Servidor Paralelo">PSGI</abbr>
|
||||
* <abbr title="Getting Things Done - Fazer as Coisas">GTD</abbr>
|
||||
* <abbr title="less than - menos que"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token - Token Web XML">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface - Interface de Gateway de Servidor Paralelo">PSGI</abbr>
|
||||
|
||||
### O abbr fornece uma frase completa e uma explicação { #the-abbr-gives-a-full-phrase-and-an-explanation }
|
||||
|
||||
* <abbr title="Mozilla Developer Network – Rede de Desenvolvedores da Mozilla: documentação para desenvolvedores, escrita pelo pessoal do Firefox">MDN</abbr>
|
||||
* <abbr title="Input/Output – Entrada/Saída: leitura ou escrita em disco, comunicações de rede.">I/O</abbr>.
|
||||
* <abbr title="Mozilla Developer Network - Rede de Desenvolvedores da Mozilla: documentação para desenvolvedores, escrita pelo pessoal do Firefox">MDN</abbr>
|
||||
* <abbr title="Input/Output: leitura ou escrita em disco, comunicações de rede.">I/O</abbr>.
|
||||
|
||||
////
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ Lembre-se que você deve retornar o `JSONResponse` diretamente.
|
||||
|
||||
///
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
A chave `model` não é parte do OpenAPI.
|
||||
|
||||
@@ -183,7 +183,7 @@ Note que você deve retornar a imagem utilizando um `FileResponse` diretamente.
|
||||
|
||||
///
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
A menos que você especifique um media type diferente explicitamente em seu parâmetro `responses`, o FastAPI assumirá que o retorno possui o mesmo media type contido na classe principal de retorno (padrão `application/json`).
|
||||
|
||||
|
||||
@@ -30,12 +30,12 @@ Garanta que ele tenha toda informação que você deseja, e que os valores sejam
|
||||
|
||||
Você também pode utilizar `from starlette.responses import JSONResponse`.
|
||||
|
||||
O **FastAPI** disponibiliza o `starlette.responses` como `fastapi.responses` apenas por conveniência para você, o programador. Porém a maioria dos retornos disponíveis vem diretamente do Starlette. O mesmo com `status`.
|
||||
O **FastAPI** disponibiliza o `starlette.responses` como `fastapi.responses` apenas por conveniência para você, o programador. Porém a maioria das respostas disponíveis vem diretamente do Starlette. O mesmo com `status`.
|
||||
|
||||
///
|
||||
|
||||
## OpenAPI e documentação da API { #openapi-and-api-docs }
|
||||
|
||||
Se você retorna códigos de status adicionais e retornos diretamente, eles não serão incluídos no esquema do OpenAPI (a documentação da API), porque o FastAPI não tem como saber de antemão o que será retornado.
|
||||
Se você retorna códigos de status adicionais e respostas diretamente, eles não serão incluídos no esquema do OpenAPI (a documentação da API), porque o FastAPI não tem como saber de antemão o que será retornado.
|
||||
|
||||
Mas você pode documentar isso no seu código, utilizando: [Retornos Adicionais](additional-responses.md).
|
||||
Mas você pode documentar isso no seu código, utilizando: [Respostas Adicionais](additional-responses.md).
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Dependências avançadas { #advanced-dependencies }
|
||||
|
||||
|
||||
## Dependências parametrizadas { #parameterized-dependencies }
|
||||
|
||||
Todas as dependências que vimos até agora são funções ou classes fixas.
|
||||
@@ -98,7 +99,7 @@ Por exemplo, se você tivesse uma sessão de banco de dados em uma dependência
|
||||
|
||||
Esse comportamento foi revertido na versão 0.118.0, para que o código de saída após o `yield` seja executado depois que a resposta for enviada.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Como você verá abaixo, isso é muito semelhante ao comportamento antes da versão 0.106.0, mas com várias melhorias e correções de bugs para casos extremos.
|
||||
|
||||
@@ -108,7 +109,7 @@ Como você verá abaixo, isso é muito semelhante ao comportamento antes da vers
|
||||
|
||||
Há alguns casos de uso, com condições específicas, que poderiam se beneficiar do comportamento antigo de executar o código de saída das dependências com `yield` antes de enviar a resposta.
|
||||
|
||||
Por exemplo, imagine que você tem código que usa uma sessão de banco de dados em uma dependência com `yield` apenas para verificar um usuário, mas a sessão de banco de dados nunca é usada novamente na *função de operação de rota*, somente na dependência, e a resposta demora a ser enviada, como um `StreamingResponse` que envia dados lentamente, mas por algum motivo não usa o banco de dados.
|
||||
Por exemplo, imagine que você tem código que usa uma sessão de banco de dados em uma dependência com `yield` apenas para verificar um usuário, mas a sessão de banco de dados nunca é usada novamente na *função de operação de rota*, somente na dependência, e a response demora a ser enviada, como um `StreamingResponse` que envia dados lentamente, mas por algum motivo não usa o banco de dados.
|
||||
|
||||
Nesse caso, a sessão de banco de dados seria mantida até que a resposta termine de ser enviada, mas se você não a usa, então não seria necessário mantê-la.
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ Para retornar uma resposta com HTML diretamente do **FastAPI**, utilize `HTMLRes
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
O parâmetro `response_class` também será usado para definir o "media type" da resposta.
|
||||
|
||||
@@ -65,7 +65,7 @@ Uma `Response` retornada diretamente em sua *função de operação de rota* nã
|
||||
|
||||
///
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Obviamente, o cabeçalho `Content-Type`, o código de status, etc, virão do objeto `Response` que você retornou.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Mas o FastAPI também suporta o uso de [`dataclasses`](https://docs.python.org/3
|
||||
|
||||
Isso ainda é suportado graças ao **Pydantic**, pois ele tem [suporte interno para `dataclasses`](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel).
|
||||
|
||||
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.
|
||||
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 própria versão de dataclasses do Pydantic.
|
||||
|
||||
E claro, ele suporta o mesmo:
|
||||
|
||||
@@ -18,7 +18,7 @@ E claro, ele suporta o mesmo:
|
||||
|
||||
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
|
||||
/// note | Nota
|
||||
|
||||
Lembre-se de que dataclasses não podem fazer tudo o que os modelos Pydantic podem fazer.
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Eventos de lifespan { #lifespan-events }
|
||||
|
||||
|
||||
Você pode definir a lógica (código) que deve ser executada antes da aplicação **inicializar**. Isso significa que esse código será executado **uma vez**, **antes** de a aplicação **começar a receber requisições**.
|
||||
|
||||
Da mesma forma, você pode definir a lógica (código) que deve ser executada quando a aplicação estiver **encerrando**. Nesse caso, esse código será executado **uma vez**, **depois** de possivelmente ter tratado **várias requisições**.
|
||||
@@ -120,7 +121,7 @@ Para adicionar uma função que deve ser executada quando a aplicação estiver
|
||||
|
||||
Aqui, a função de manipulador do evento `shutdown` escreverá uma linha de texto `"Application shutdown"` no arquivo `log.txt`.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Na função `open()`, o `mode="a"` significa "acrescentar", então a linha será adicionada depois do que já estiver naquele arquivo, sem sobrescrever o conteúdo anterior.
|
||||
|
||||
@@ -152,7 +153,7 @@ Apenas um detalhe técnico para nerds curiosos. 🤓
|
||||
|
||||
Por baixo, na especificação técnica do ASGI, isso é parte do [Protocolo Lifespan](https://asgi.readthedocs.io/en/latest/specs/lifespan.html), e define eventos chamados `startup` e `shutdown`.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Você pode ler mais sobre os manipuladores de `lifespan` do Starlette na [Documentação do Lifespan do Starlette](https://www.starlette.dev/lifespan/).
|
||||
|
||||
|
||||
@@ -20,28 +20,13 @@ O FastAPI gera automaticamente especificações **OpenAPI 3.1**, então qualquer
|
||||
|
||||
///
|
||||
|
||||
## Geradores de SDK dos patrocinadores do FastAPI { #sdk-generators-from-fastapi-sponsors }
|
||||
|
||||
Esta seção destaca soluções **financiadas por investimento** e **com suporte de empresas** que patrocinam o FastAPI. Esses produtos fornecem **funcionalidades adicionais** e **integrações** além de SDKs gerados com alta qualidade.
|
||||
|
||||
Ao ✨ [**patrocinar o FastAPI**](../help-fastapi.md#sponsor-the-author) ✨, essas empresas ajudam a garantir que o framework e seu **ecossistema** continuem saudáveis e **sustentáveis**.
|
||||
|
||||
O patrocínio também demonstra um forte compromisso com a **comunidade** FastAPI (você), mostrando que elas se importam não apenas em oferecer um **ótimo serviço**, mas também em apoiar um **framework robusto e próspero**, o FastAPI. 🙇
|
||||
|
||||
Por exemplo, você pode querer experimentar:
|
||||
|
||||
* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)
|
||||
* [liblab](https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi)
|
||||
|
||||
Algumas dessas soluções também podem ser open source ou oferecer planos gratuitos, para que você possa testá-las sem compromisso financeiro. Outros geradores comerciais de SDK estão disponíveis e podem ser encontrados online. 🤓
|
||||
|
||||
## Crie um SDK em TypeScript { #create-a-typescript-sdk }
|
||||
|
||||
Vamos começar com uma aplicação FastAPI simples:
|
||||
|
||||
{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}
|
||||
|
||||
Observe que as *operações de rota* definem os modelos que usam para o corpo da requisição e o corpo da resposta, usando os modelos `Item` e `ResponseMessage`.
|
||||
Observe que as *operações de rota* definem os modelos que usam para o payload da requisição e o payload da resposta, usando os modelos `Item` e `ResponseMessage`.
|
||||
|
||||
### Documentação da API { #api-docs }
|
||||
|
||||
@@ -73,7 +58,7 @@ Agora você pode importar e usar o código do cliente. Poderia ser assim, observ
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image02.png">
|
||||
|
||||
Você também obterá preenchimento automático para o corpo a ser enviado:
|
||||
Você também obterá preenchimento automático para o payload a enviar:
|
||||
|
||||
<img src="/img/tutorial/generate-clients/image03.png">
|
||||
|
||||
@@ -122,7 +107,7 @@ ItemsService.createItemItemsPost({name: "Plumbus", price: 5})
|
||||
|
||||
...isso ocorre porque o gerador de clientes usa o **ID de operação interno do OpenAPI** para cada *operação de rota*.
|
||||
|
||||
O OpenAPI exige que cada ID de operação seja único em todas as *operações de rota*, então o FastAPI usa o **nome da função**, o **path** e o **método HTTP** para gerar esse ID de operação, porque dessa forma ele pode garantir que os IDs de operação sejam únicos.
|
||||
O OpenAPI exige que cada ID de operação seja único em todas as *operações de rota*, então o FastAPI usa o **nome da função**, o **path** e o **método/operação HTTP** para gerar esse ID de operação, porque dessa forma ele pode garantir que os IDs de operação sejam únicos.
|
||||
|
||||
Mas eu vou te mostrar como melhorar isso a seguir. 🤓
|
||||
|
||||
@@ -195,8 +180,8 @@ Depois de gerar o novo cliente, você terá agora **nomes de métodos “limpos
|
||||
Ao usar os clientes gerados automaticamente, você terá **preenchimento automático** para:
|
||||
|
||||
* Métodos.
|
||||
* Corpos de requisições, parâmetros de query, etc.
|
||||
* Corpos de respostas.
|
||||
* Payloads de requisições no body, parâmetros de query, etc.
|
||||
* Payloads de respostas.
|
||||
|
||||
Você também terá **erros em linha** para tudo.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Se sua aplicação precisa receber e enviar dados JSON, mas você precisa inclui
|
||||
|
||||
## Base64 vs Arquivos { #base64-vs-files }
|
||||
|
||||
Primeiro, considere se você pode usar [Arquivos na request](../tutorial/request-files.md) para fazer upload de dados binários e [Response personalizada - FileResponse](./custom-response.md#fileresponse--fileresponse-) para enviar dados binários, em vez de codificá-los em JSON.
|
||||
Primeiro, considere se você pode usar [Arquivos na request](../tutorial/request-files.md) para fazer upload de dados binários e [Response personalizada - FileResponse](./custom-response.md#fileresponse) para enviar dados binários, em vez de codificá-los em JSON.
|
||||
|
||||
JSON só pode conter strings codificadas em UTF-8, portanto não pode conter bytes puros.
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# Callbacks na OpenAPI { #openapi-callbacks }
|
||||
|
||||
Você poderia criar uma API com uma *operação de rota* que poderia acionar um request a uma *API externa* criada por outra pessoa (provavelmente o mesmo desenvolvedor que estaria *usando* sua API).
|
||||
Você poderia criar uma API com uma *operação de rota* que poderia acionar um request para uma *API externa* criada por outra pessoa (provavelmente o mesmo desenvolvedor que estaria *usando* sua API).
|
||||
|
||||
O processo que acontece quando sua aplicação de API chama a *API externa* é chamado de "callback". Porque o software que o desenvolvedor externo escreveu envia um request para sua API e então sua API *chama de volta*, enviando um request para uma *API externa* (que provavelmente foi criada pelo mesmo desenvolvedor).
|
||||
|
||||
Nesse caso, você poderia querer documentar como essa API externa *deveria* ser. Que *operação de rota* ela deveria ter, que corpo ela deveria esperar, que resposta ela deveria retornar, etc.
|
||||
|
||||
## Um aplicativo com callbacks { #an-app-with-callbacks }
|
||||
## Uma aplicação com callbacks { #an-app-with-callbacks }
|
||||
|
||||
Vamos ver tudo isso com um exemplo.
|
||||
|
||||
Imagine que você desenvolve um aplicativo que permite criar faturas.
|
||||
Imagine que você desenvolve uma aplicação que permite criar faturas.
|
||||
|
||||
Essas faturas terão um `id`, `title` (opcional), `customer` e `total`.
|
||||
|
||||
@@ -23,11 +23,11 @@ Então sua API irá (vamos imaginar):
|
||||
* Enviar a notificação de volta para o usuário da API (o desenvolvedor externo).
|
||||
* Isso será feito enviando um request POST (de *sua API*) para alguma *API externa* fornecida por esse desenvolvedor externo (este é o "callback").
|
||||
|
||||
## O aplicativo **FastAPI** normal { #the-normal-fastapi-app }
|
||||
## A aplicação **FastAPI** normal { #the-normal-fastapi-app }
|
||||
|
||||
Vamos primeiro ver como o aplicativo da API normal se pareceria antes de adicionar o callback.
|
||||
Vamos primeiro ver como a aplicação da API normal se pareceria antes de adicionar o callback.
|
||||
|
||||
Ele terá uma *operação de rota* que receberá um corpo `Invoice`, e um parâmetro de consulta `callback_url` que conterá a URL para o callback.
|
||||
Ela terá uma *operação de rota* que receberá um corpo `Invoice`, e um parâmetro de consulta `callback_url` que conterá a URL para o callback.
|
||||
|
||||
Essa parte é bastante normal, a maior parte do código provavelmente já é familiar para você:
|
||||
|
||||
@@ -45,7 +45,7 @@ A única novidade é o `callbacks=invoices_callback_router.routes` como argument
|
||||
|
||||
O código real do callback dependerá muito da sua própria aplicação de API.
|
||||
|
||||
E provavelmente variará muito de um aplicativo para o outro.
|
||||
E provavelmente variará muito de uma aplicação para outra.
|
||||
|
||||
Poderia ser apenas uma ou duas linhas de código, como:
|
||||
|
||||
@@ -72,7 +72,7 @@ Ao implementar o callback por conta própria, você pode usar algo como [HTTPX](
|
||||
|
||||
## Escreva o código de documentação do callback { #write-the-callback-documentation-code }
|
||||
|
||||
Esse código não será executado em seu aplicativo, nós só precisamos dele para *documentar* como essa *API externa* deveria ser.
|
||||
Esse código não será executado em sua aplicação, nós só precisamos dele para *documentar* como essa *API externa* deveria ser.
|
||||
|
||||
Mas, você já sabe como criar facilmente documentação automática para uma API com o **FastAPI**.
|
||||
|
||||
@@ -105,7 +105,7 @@ Ela deve parecer exatamente como uma *operação de rota* normal do FastAPI:
|
||||
|
||||
Há 2 diferenças principais de uma *operação de rota* normal:
|
||||
|
||||
* Ela não necessita ter nenhum código real, porque seu aplicativo nunca chamará esse código. Ele é usado apenas para documentar a *API externa*. Então, a função poderia ter apenas `pass`.
|
||||
* Ela não necessita ter nenhum código real, porque sua aplicação nunca chamará esse código. Ele é usado apenas para documentar a *API externa*. Então, a função poderia ter apenas `pass`.
|
||||
* O *path* pode conter uma [expressão OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) (veja mais abaixo) em que pode usar variáveis com parâmetros e partes do request original enviado para *sua API*.
|
||||
|
||||
### A expressão do path do callback { #the-callback-path-expression }
|
||||
@@ -163,23 +163,23 @@ Perceba como a URL de callback usada contém a URL recebida como um parâmetro d
|
||||
|
||||
///
|
||||
|
||||
### Adicione o roteador de callback { #add-the-callback-router }
|
||||
### Adicione o router de callback { #add-the-callback-router }
|
||||
|
||||
Nesse ponto você tem a(s) *operação(ões) de rota de callback* necessária(s) (a(s) que o *desenvolvedor externo* deveria implementar na *API externa*) no roteador de callback que você criou acima.
|
||||
Nesse ponto você tem a(s) *operação(ões) de rota de callback* necessária(s) (a(s) que o *desenvolvedor externo* deveria implementar na *API externa*) no router de callback que você criou acima.
|
||||
|
||||
Agora use o parâmetro `callbacks` no decorador da *operação de rota da sua API* para passar o atributo `.routes` (que é na verdade apenas uma `list` de rotas/*operações de path*) do roteador de callback:
|
||||
Agora use o parâmetro `callbacks` no decorador da *operação de rota da sua API* para passar o atributo `.routes` desse router de callback:
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Perceba que você não está passando o roteador em si (`invoices_callback_router`) para `callback=`, mas o atributo `.routes`, como em `invoices_callback_router.routes`.
|
||||
Perceba que você não está passando o router em si (`invoices_callback_router`) para `callbacks=`, mas seu `.routes`, como em `invoices_callback_router.routes`. FastAPI usará essas rotas para gerar a documentação OpenAPI do callback.
|
||||
|
||||
///
|
||||
|
||||
### Verifique a documentação { #check-the-docs }
|
||||
|
||||
Agora você pode iniciar seu aplicativo e ir para [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
|
||||
Agora você pode iniciar sua aplicação e ir para [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
|
||||
|
||||
Você verá sua documentação incluindo uma seção "Callbacks" para sua *operação de rota* que mostra como a *API externa* deveria ser:
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ Com o **FastAPI**, utilizando o OpenAPI, você pode definir os nomes destes webh
|
||||
|
||||
Isto pode facilitar bastante para os seus usuários **implementarem as APIs deles** para receber as requisições dos seus **webhooks**, eles podem inclusive ser capazes de gerar parte do código da API deles.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Webhooks estão disponíveis a partir do OpenAPI 3.1.0, e possui suporte do FastAPI a partir da versão `0.99.0`.
|
||||
|
||||
@@ -36,7 +36,7 @@ Quando você cria uma aplicação com o **FastAPI**, existe um atributo chamado
|
||||
|
||||
Os webhooks que você define aparecerão no esquema do **OpenAPI** e na **página de documentação** gerada automaticamente.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
O objeto `app.webhooks` é na verdade apenas um `APIRouter`, o mesmo tipo que você utilizaria ao estruturar a sua aplicação com diversos arquivos.
|
||||
|
||||
|
||||
@@ -16,17 +16,11 @@ Você deveria ter certeza que ele é único para cada operação.
|
||||
|
||||
### Utilizando o nome da *função de operação de rota* como o operationId { #using-the-path-operation-function-name-as-the-operationid }
|
||||
|
||||
Se você quiser utilizar o nome das funções da sua API como `operationId`s, você pode iterar sobre todos esses nomes e sobrescrever o `operation_id` em cada *operação de rota* utilizando o `APIRoute.name` dela.
|
||||
Se você quiser utilizar os nomes das funções da sua API como `operationId`s, você pode passar uma `generate_unique_id_function` personalizada para o `FastAPI`.
|
||||
|
||||
Você deveria fazer isso depois de adicionar todas as suas *operações de rota*.
|
||||
A função recebe cada `APIRoute` e retorna o `operationId` a ser usado para aquela operação de rota.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Se você chamar `app.openapi()` manualmente, você deveria atualizar os `operationId`s antes dessa chamada.
|
||||
|
||||
///
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2,5:6,9] *}
|
||||
|
||||
/// warning | Atenção
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ Para estes casos, você pode utilizar um parâmetro `Response`.
|
||||
|
||||
Você pode declarar um parâmetro do tipo `Response` em sua *função de operação de rota* (assim como você pode fazer para cookies e headers).
|
||||
|
||||
E então você pode definir o `status_code` neste objeto de retorno *temporal*.
|
||||
E então você pode definir o `status_code` neste objeto de retorno *temporário*.
|
||||
|
||||
{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}
|
||||
|
||||
@@ -26,6 +26,6 @@ E então você pode retornar qualquer objeto que você precise, como você faria
|
||||
|
||||
E se você declarar um `response_model`, ele ainda será utilizado para filtrar e converter o objeto que você retornou.
|
||||
|
||||
O **FastAPI** utilizará este retorno *temporal* para extrair o código de status (e também cookies e headers), e irá colocá-los no retorno final que contém o valor que você retornou, filtrado por qualquer `response_model`.
|
||||
O **FastAPI** utilizará este retorno *temporário* para extrair o código de status (e também cookies e headers), e irá colocá-los no retorno final que contém o valor que você retornou, filtrado por qualquer `response_model`.
|
||||
|
||||
Você também pode declarar o parâmetro `Response` nas dependências, e definir o código de status nelas. Mas lembre-se que o último que for definido é o que prevalecerá.
|
||||
|
||||
@@ -30,7 +30,7 @@ Então, defina os cookies nela e a retorne:
|
||||
|
||||
Lembre-se de que se você retornar uma resposta diretamente em vez de usar o parâmetro `Response`, FastAPI a retornará diretamente.
|
||||
|
||||
Portanto, você terá que garantir que seus dados sejam do tipo correto. E.g. será compatível com JSON se você estiver retornando um `JSONResponse`.
|
||||
Portanto, você terá que garantir que seus dados sejam do tipo correto. Por exemplo, será compatível com JSON se você estiver retornando um `JSONResponse`.
|
||||
|
||||
E também que você não esteja enviando nenhum dado que deveria ter sido filtrado por um `response_model`.
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ Normalmente você terá um desempenho muito melhor usando um [Modelo de resposta
|
||||
|
||||
Você pode retornar uma `Response` ou qualquer subclasse dela.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
A própria `JSONResponse` é uma subclasse de `Response`.
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Cabeçalhos de resposta { #response-headers }
|
||||
|
||||
|
||||
## Use um parâmetro `Response` { #use-a-response-parameter }
|
||||
|
||||
Você pode declarar um parâmetro do tipo `Response` na sua *função de operação de rota* (assim como você pode fazer para cookies).
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
Você pode utilizar escopos do OAuth2 diretamente com o **FastAPI**, eles são integrados para funcionar perfeitamente.
|
||||
|
||||
Isso permitiria que você tivesse um sistema de permissionamento mais refinado, seguindo o padrão do OAuth2 integrado na sua aplicação OpenAPI (e as documentações da API).
|
||||
Isso permitiria que você tivesse um sistema de permissionamento mais refinado, seguindo o padrão OAuth2, integrado na sua aplicação OpenAPI (e a documentação da API).
|
||||
|
||||
OAuth2 com escopos é o mecanismo utilizado por muitos provedores de autenticação, como o Facebook, Google, GitHub, Microsoft, X (Twitter), etc. Eles utilizam isso para prover permissões específicas para os usuários e aplicações.
|
||||
OAuth2 com escopos é o mecanismo utilizado por muitos grandes provedores de autenticação, como o Facebook, Google, GitHub, Microsoft, X (Twitter), etc. Eles utilizam isso para prover permissões específicas para os usuários e aplicações.
|
||||
|
||||
Toda vez que você "se autentica com" Facebook, Google, GitHub, Microsoft, X (Twitter), aquela aplicação está utilizando o OAuth2 com escopos.
|
||||
|
||||
@@ -34,7 +34,7 @@ O conteúdo de cada uma dessas strings pode ter qualquer formato, mas não devem
|
||||
|
||||
Estes escopos representam "permissões".
|
||||
|
||||
No OpenAPI (e.g. os documentos da API), você pode definir "esquemas de segurança".
|
||||
No OpenAPI (por exemplo, a documentação da API), você pode definir "esquemas de segurança".
|
||||
|
||||
Quando um desses esquemas de segurança utiliza OAuth2, você pode também declarar e utilizar escopos.
|
||||
|
||||
@@ -42,11 +42,11 @@ Cada "escopo" é apenas uma string (sem espaços).
|
||||
|
||||
Eles são normalmente utilizados para declarar permissões de segurança específicas, como por exemplo:
|
||||
|
||||
* `users:read` or `users:write` são exemplos comuns.
|
||||
* `users:read` ou `users:write` são exemplos comuns.
|
||||
* `instagram_basic` é utilizado pelo Facebook / Instagram.
|
||||
* `https://www.googleapis.com/auth/drive` é utilizado pelo Google.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
No OAuth2, um "escopo" é apenas uma string que declara uma permissão específica necessária.
|
||||
|
||||
@@ -60,7 +60,7 @@ Para o OAuth2, eles são apenas strings.
|
||||
|
||||
## Visão global { #global-view }
|
||||
|
||||
Primeiro, vamos olhar rapidamente as partes que mudam dos exemplos do **Tutorial - Guia de Usuário** para [OAuth2 com Senha (e hash), Bearer com tokens JWT](../../tutorial/security/oauth2-jwt.md). Agora utilizando escopos OAuth2:
|
||||
Primeiro, vamos olhar rapidamente as partes que mudam dos exemplos no **Tutorial - Guia de Usuário** principal para [OAuth2 com Senha (e hash), Bearer com tokens JWT](../../tutorial/security/oauth2-jwt.md). Agora utilizando escopos OAuth2:
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}
|
||||
|
||||
@@ -74,7 +74,7 @@ O parâmetro `scopes` recebe um `dict` contendo cada escopo como chave e a descr
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}
|
||||
|
||||
Pelo motivo de estarmos declarando estes escopos, eles aparecerão nos documentos da API quando você se autenticar/autorizar.
|
||||
Pelo motivo de estarmos declarando estes escopos, eles aparecerão na documentação da API quando você se autenticar/autorizar.
|
||||
|
||||
E você poderá selecionar quais escopos você deseja dar acesso: `me` e `items`.
|
||||
|
||||
@@ -108,7 +108,7 @@ Para isso, nós importamos e utilizamos `Security` de `fastapi`.
|
||||
|
||||
Você pode utilizar `Security` para declarar dependências (assim como `Depends`), porém o `Security` também recebe o parâmetro `scopes` com uma lista de escopos (strings).
|
||||
|
||||
Neste caso, nós passamos a função `get_current_active_user` como dependência para `Security` (da mesma forma que nós faríamos com `Depends`).
|
||||
Neste caso, nós passamos a função de dependência `get_current_active_user` para `Security` (da mesma forma que nós faríamos com `Depends`).
|
||||
|
||||
Mas nós também passamos uma `list` de escopos, neste caso com apenas um escopo: `items` (poderia ter mais).
|
||||
|
||||
@@ -142,7 +142,7 @@ Agora atualize a dependência `get_current_user`.
|
||||
|
||||
Este é o usado pelas dependências acima.
|
||||
|
||||
Aqui é onde estamos utilizando o mesmo esquema OAuth2 que nós declaramos antes, declarando-o como uma dependência: `oauth2_scheme`.
|
||||
Aqui é onde estamos utilizando o mesmo esquema OAuth2 que nós criamos antes, declarando-o como uma dependência: `oauth2_scheme`.
|
||||
|
||||
Porque esta função de dependência não possui nenhum requerimento de escopo, nós podemos utilizar `Depends` com o `oauth2_scheme`. Nós não precisamos utilizar `Security` quando nós não precisamos especificar escopos de segurança.
|
||||
|
||||
@@ -235,7 +235,7 @@ Todos eles serão validados independentemente para cada *operação de rota*.
|
||||
|
||||
## Verifique { #check-it }
|
||||
|
||||
Se você abrir os documentos da API, você pode autenticar e especificar quais escopos você quer autorizar.
|
||||
Se você abrir a documentação da API, você pode autenticar e especificar quais escopos você quer autorizar.
|
||||
|
||||
<img src="/img/tutorial/security/image11.png">
|
||||
|
||||
@@ -249,11 +249,11 @@ Isso é o que aconteceria se uma aplicação terceira que tentou acessar uma des
|
||||
|
||||
Neste exemplo nós estamos utilizando o fluxo de senha do OAuth2.
|
||||
|
||||
Isso é apropriado quando nós estamos autenticando em nossa própria aplicação, provavelmente com o nosso próprio "*frontend*".
|
||||
Isso é apropriado quando nós estamos autenticando em nossa própria aplicação, provavelmente com o nosso próprio frontend.
|
||||
|
||||
Porque nós podemos confiar nele para receber o `username` e o `password`, pois nós controlamos isso.
|
||||
|
||||
Mas se nós estamos construindo uma aplicação OAuth2 que outros poderiam conectar (i.e., se você está construindo um provedor de autenticação equivalente ao Facebook, Google, GitHub, etc.) você deveria utilizar um dos outros fluxos.
|
||||
Mas se nós estamos construindo uma aplicação OAuth2 que outros poderiam conectar (ou seja, se você está construindo um provedor de autenticação equivalente ao Facebook, Google, GitHub, etc.) você deveria utilizar um dos outros fluxos.
|
||||
|
||||
O mais comum é o fluxo implícito.
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Configurações e Variáveis de Ambiente { #settings-and-environment-variables }
|
||||
|
||||
|
||||
Em muitos casos, sua aplicação pode precisar de configurações externas, por exemplo chaves secretas, credenciais de banco de dados, credenciais para serviços de e-mail, etc.
|
||||
|
||||
A maioria dessas configurações é variável (pode mudar), como URLs de banco de dados. E muitas podem ser sensíveis, como segredos.
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
Se você quer transmitir dados que podem ser estruturados como JSON, você deveria [Transmitir JSON Lines](../tutorial/stream-json-lines.md).
|
||||
|
||||
Mas se você quer transmitir dados binários puros ou strings, veja como fazer.
|
||||
Mas se você quer **transmitir dados binários puros** ou strings, veja como fazer.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Adicionado no FastAPI 0.134.0.
|
||||
|
||||
@@ -12,15 +12,15 @@ Adicionado no FastAPI 0.134.0.
|
||||
|
||||
## Casos de uso { #use-cases }
|
||||
|
||||
Você pode usar isto para transmitir strings puras, por exemplo diretamente da saída de um serviço de AI LLM.
|
||||
Você pode usar isto para transmitir strings puras, por exemplo diretamente da saída de um serviço de **AI LLM**.
|
||||
|
||||
Você também pode usá-lo para transmitir arquivos binários grandes, enviando cada bloco de dados à medida que o lê, sem precisar carregar tudo na memória de uma vez.
|
||||
Você também pode usá-lo para transmitir **arquivos binários grandes**, enviando cada bloco de dados à medida que o lê, sem precisar carregar tudo na memória de uma vez.
|
||||
|
||||
Você também pode transmitir vídeo ou áudio desta forma; pode até ser gerado enquanto você processa e envia.
|
||||
Você também pode transmitir **vídeo** ou **áudio** desta forma; pode até ser gerado enquanto você processa e envia.
|
||||
|
||||
## Um `StreamingResponse` com `yield` { #a-streamingresponse-with-yield }
|
||||
|
||||
Se você declarar `response_class=StreamingResponse` na sua função de operação de rota, você pode usar `yield` para enviar cada bloco de dados em sequência.
|
||||
Se você declarar `response_class=StreamingResponse` na sua *função de operação de rota*, você pode usar `yield` para enviar cada bloco de dados em sequência.
|
||||
|
||||
{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}
|
||||
|
||||
@@ -40,7 +40,7 @@ Como o FastAPI não tentará converter os dados para JSON com Pydantic nem seria
|
||||
|
||||
{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}
|
||||
|
||||
Isso também significa que, com `StreamingResponse`, você tem a liberdade e a responsabilidade de produzir e codificar os bytes exatamente como precisam ser enviados, independentemente das anotações de tipo. 🤓
|
||||
Isso também significa que, com `StreamingResponse`, você tem a **liberdade** e a **responsabilidade** de produzir e codificar os bytes exatamente como precisam ser enviados, independentemente das anotações de tipo. 🤓
|
||||
|
||||
### Transmitir bytes { #stream-bytes }
|
||||
|
||||
@@ -50,7 +50,7 @@ Um dos principais casos de uso é transmitir `bytes` em vez de strings; você po
|
||||
|
||||
## Um `PNGStreamingResponse` personalizado { #a-custom-pngstreamingresponse }
|
||||
|
||||
Nos exemplos acima, os bytes eram transmitidos, mas a resposta não tinha um cabeçalho `Content-Type`, então o cliente não sabia que tipo de dado estava recebendo.
|
||||
Nos exemplos acima, os bytes eram transmitidos, mas a response não tinha um cabeçalho `Content-Type`, então o cliente não sabia que tipo de dado estava recebendo.
|
||||
|
||||
Você pode criar uma subclasse personalizada de `StreamingResponse` que define o cabeçalho `Content-Type` para o tipo de dado que você está transmitindo.
|
||||
|
||||
@@ -58,7 +58,7 @@ Por exemplo, você pode criar um `PNGStreamingResponse` que define o cabeçalho
|
||||
|
||||
{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}
|
||||
|
||||
Em seguida, você pode usar essa nova classe em `response_class=PNGStreamingResponse` na sua função de operação de rota:
|
||||
Em seguida, você pode usar essa nova classe em `response_class=PNGStreamingResponse` na sua *função de operação de rota*:
|
||||
|
||||
{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}
|
||||
|
||||
@@ -78,7 +78,7 @@ Apenas para que possa viver no mesmo arquivo deste exemplo e você possa copiar
|
||||
|
||||
///
|
||||
|
||||
Ao usar um bloco `with`, garantimos que o objeto semelhante a arquivo seja fechado após a função geradora (a função com `yield`) terminar. Ou seja, após terminar de enviar a resposta.
|
||||
Ao usar um bloco `with`, garantimos que o objeto semelhante a arquivo seja fechado após a função geradora (a função com `yield`) terminar. Ou seja, após terminar de enviar a response.
|
||||
|
||||
Isso não seria tão importante neste exemplo específico porque é um arquivo falso em memória (com `io.BytesIO`), mas com um arquivo real, seria importante garantir que o arquivo fosse fechado ao final do trabalho.
|
||||
|
||||
@@ -90,7 +90,7 @@ Por exemplo, eles não têm `await file.read()`, nem `async for chunk in file`.
|
||||
|
||||
E, em muitos casos, lê-los seria uma operação bloqueante (que poderia bloquear o loop de eventos), pois são lidos do disco ou da rede.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
O exemplo acima é, na verdade, uma exceção, porque o objeto `io.BytesIO` já está em memória, então lê-lo não bloqueará nada.
|
||||
|
||||
@@ -98,7 +98,7 @@ Mas, em muitos casos, ler um arquivo ou um objeto semelhante a arquivo bloqueari
|
||||
|
||||
///
|
||||
|
||||
Para evitar bloquear o loop de eventos, você pode simplesmente declarar a função de operação de rota com `def` normal em vez de `async def`. Assim, o FastAPI a executará em um worker de threadpool, evitando bloquear o loop principal.
|
||||
Para evitar bloquear o loop de eventos, você pode simplesmente declarar a *função de operação de rota* com `def` normal em vez de `async def`. Assim, o FastAPI a executará em um worker de threadpool, evitando bloquear o loop principal.
|
||||
|
||||
{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Verificação Estrita de Content-Type { #strict-content-type-checking }
|
||||
|
||||
Por padrão, o **FastAPI** usa verificação estrita do cabeçalho `Content-Type` para corpos de requisição JSON; isso significa que requisições JSON devem incluir um `Content-Type` válido (por exemplo, `application/json`) para que o corpo seja interpretado como JSON.
|
||||
Por padrão, o **FastAPI** usa verificação estrita do cabeçalho `Content-Type` para corpos de requisição JSON; isso significa que requisições JSON **devem** incluir um `Content-Type` válido (por exemplo, `application/json`) para que o corpo seja interpretado como JSON.
|
||||
|
||||
## Risco de CSRF { #csrf-risk }
|
||||
|
||||
@@ -40,7 +40,7 @@ Observe que ambos têm o mesmo host.
|
||||
|
||||
Usando o frontend, você pode fazer o agente de IA executar ações em seu nome.
|
||||
|
||||
Como está em execução localmente e não na Internet aberta, você decide não configurar autenticação, confiando apenas no acesso à rede local.
|
||||
Como está em execução **localmente** e não na Internet aberta, você decide **não configurar autenticação**, confiando apenas no acesso à rede local.
|
||||
|
||||
Então um de seus usuários poderia instalá-lo e executá-lo localmente.
|
||||
|
||||
@@ -69,9 +69,9 @@ Se sua aplicação está na Internet aberta, você não “confiaria na rede”
|
||||
|
||||
Atacantes poderiam simplesmente executar um script para enviar requisições à sua API, sem necessidade de interação do navegador, então você provavelmente já está protegendo quaisquer endpoints privilegiados.
|
||||
|
||||
Nesse caso, esse ataque/risco não se aplica a você.
|
||||
Nesse caso, **esse ataque/risco não se aplica a você**.
|
||||
|
||||
Esse risco e ataque é relevante principalmente quando a aplicação roda na rede local e essa é a única proteção presumida.
|
||||
Esse risco e ataque é relevante principalmente quando a aplicação roda na **rede local** e essa é a **única proteção presumida**.
|
||||
|
||||
## Permitindo Requisições sem Content-Type { #allowing-requests-without-content-type }
|
||||
|
||||
@@ -81,7 +81,7 @@ Se você precisa dar suporte a clientes que não enviam um cabeçalho `Content-T
|
||||
|
||||
Com essa configuração, requisições sem um cabeçalho `Content-Type` terão o corpo interpretado como JSON, o mesmo comportamento das versões mais antigas do FastAPI.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Esse comportamento e configuração foram adicionados no FastAPI 0.132.0.
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ Eles funcionam da mesma forma que para outros endpoints FastAPI/*operações de
|
||||
|
||||
{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Como isso é um WebSocket, não faz muito sentido levantar uma `HTTPException`, em vez disso levantamos uma `WebSocketException`.
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
# Adicionando WSGI - Flask, Django, entre outros { #including-wsgi-flask-django-others }
|
||||
|
||||
|
||||
Como você viu em [Subaplicações - Montagens](sub-applications.md) e [Atrás de um Proxy](behind-a-proxy.md), você pode montar aplicações WSGI.
|
||||
|
||||
Para isso, você pode utilizar o `WSGIMiddleware` para encapsular a sua aplicação WSGI, como por exemplo Flask, Django, etc.
|
||||
|
||||
## Usando `WSGIMiddleware` { #using-wsgimiddleware }
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Isso requer instalar `a2wsgi`, por exemplo com `pip install a2wsgi`.
|
||||
|
||||
|
||||
@@ -18,13 +18,13 @@ Mas em algum momento, não havia outra opção senão criar algo que fornecesse
|
||||
|
||||
É o framework Python mais popular e amplamente confiável. É utilizado para construir sistemas como o Instagram.
|
||||
|
||||
É relativamente bem acoplado com bancos de dados relacionais (como MySQL ou PostgreSQL), então, ter um banco de dados NoSQL (como Couchbase, MongoDB, Cassandra, etc.) como mecanismo principal de armazenamento não é muito fácil.
|
||||
É relativamente fortemente acoplado com bancos de dados relacionais (como MySQL ou PostgreSQL), então, ter um banco de dados NoSQL (como Couchbase, MongoDB, Cassandra, etc.) como mecanismo principal de armazenamento não é muito fácil.
|
||||
|
||||
Foi criado para gerar o HTML no backend, não para criar APIs usadas por um frontend moderno (como React, Vue.js e Angular) ou por outros sistemas (como dispositivos <abbr title="Internet of Things - Internet das Coisas">IoT</abbr>) comunicando com ele.
|
||||
|
||||
### [Django REST Framework](https://www.django-rest-framework.org/) { #django-rest-framework }
|
||||
|
||||
Django REST framework foi criado para ser uma caixa de ferramentas flexível para construção de APIs Web utilizando Django por baixo, para melhorar suas capacidades de API.
|
||||
Django REST Framework foi criado para ser uma caixa de ferramentas flexível para construção de APIs Web utilizando Django por baixo, para melhorar suas capacidades de API.
|
||||
|
||||
Ele é utilizado por muitas empresas incluindo Mozilla, Red Hat e Eventbrite.
|
||||
|
||||
@@ -88,7 +88,7 @@ O jeito de usar é muito simples. Por exemplo, para fazer uma requisição `GET`
|
||||
response = requests.get("http://example.com/some/url")
|
||||
```
|
||||
|
||||
A contra-parte na aplicação FastAPI, a operação de rota, poderia ficar assim:
|
||||
A *operação de rota* da API equivalente no FastAPI poderia ficar assim:
|
||||
|
||||
```Python hl_lines="1"
|
||||
@app.get("/some/url")
|
||||
@@ -377,7 +377,7 @@ Agora APIStar é um conjunto de ferramentas para validar especificações OpenAP
|
||||
|
||||
/// note | Nota
|
||||
|
||||
APIStar foi criado por Tom Christie. O mesmo cara que criou:
|
||||
APIStar foi criado por Tom Christie. A mesma pessoa que criou:
|
||||
|
||||
* Django REST Framework
|
||||
* Starlette (no qual **FastAPI** é baseado)
|
||||
|
||||
+27
-27
@@ -44,11 +44,11 @@ Se sua aplicação (de alguma forma) não tem que se comunicar com nada mais e e
|
||||
|
||||
---
|
||||
|
||||
Se você simplesmente não sabe, use apenas `def`.
|
||||
Se você simplesmente não sabe, use `def` normal.
|
||||
|
||||
---
|
||||
|
||||
**Note**: Você pode misturar `def` e `async def` nas suas *funções de operação de rota* tanto quanto necessário e definir cada função usando a melhor opção para você. FastAPI irá fazer a coisa certa com elas.
|
||||
**Nota**: Você pode misturar `def` e `async def` nas suas *funções de operação de rota* tanto quanto necessário e definir cada função usando a melhor opção para você. FastAPI irá fazer a coisa certa com elas.
|
||||
|
||||
De qualquer forma, em ambos os casos acima, FastAPI irá trabalhar assincronamente e ser extremamente rápido.
|
||||
|
||||
@@ -82,10 +82,10 @@ Esse "esperar por algo" normalmente se refere a operações <abbr title="Input a
|
||||
* conteúdo que seu programa deu ao sistema para ser escrito no disco
|
||||
* uma operação em uma API remota
|
||||
* uma operação no banco de dados finalizar
|
||||
* uma solicitação no banco de dados retornar o resultado
|
||||
* uma consulta ao banco de dados retornar os resultados
|
||||
* etc.
|
||||
|
||||
Quanto o tempo de execução é consumido majoritariamente pela espera de operações <abbr title="Input and Output - Entrada e Saída">I/O</abbr>, essas operações são chamadas operações "limitadas por I/O".
|
||||
Como o tempo de execução é consumido majoritariamente pela espera de operações <abbr title="Input and Output - Entrada e Saída">I/O</abbr>, essas operações são chamadas operações "limitadas por I/O".
|
||||
|
||||
Isso é chamado de "assíncrono" porque o computador / programa não tem que ser "sincronizado" com a tarefa lenta, esperando pelo momento exato em que a tarefa finaliza, enquanto não faz nada, para ser capaz de pegar o resultado da tarefa e dar continuidade ao trabalho.
|
||||
|
||||
@@ -109,7 +109,7 @@ Você vai com seu _crush_ na lanchonete, e fica na fila enquanto o caixa pega os
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-01.png" class="illustration">
|
||||
|
||||
Então chega a sua vez, você pede dois saborosos hambúrgueres para você e seu _crush_. 🍔🍔
|
||||
Então chega a sua vez, você pede dois saborosos hambúrgueres para você e seu _crush_. 🍔🍔
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-02.png" class="illustration">
|
||||
|
||||
@@ -189,17 +189,17 @@ Você espera, na frente do balcão 🕙, para que ninguém pegue seus hambúrgue
|
||||
|
||||
Como você e seu _crush_ estão ocupados não permitindo que ninguém passe na frente e pegue seus hambúrgueres assim que estiverem prontos, você não pode dar atenção ao seu _crush_. 😞
|
||||
|
||||
Isso é trabalho "síncrono", você está "sincronizado" com o caixa / cozinheiro 👨🍳. Você tem que esperar 🕙 e estar lá no exato momento que o caixa / cozinheiro 👨🍳 terminar os hambúrgueres e os der a você, ou então, outro alguém pode pegá-los.
|
||||
Isso é trabalho "síncrono", você está "sincronizado" com o caixa/cozinheiro 👨🍳. Você tem que esperar 🕙 e estar lá no exato momento que o caixa/cozinheiro 👨🍳 terminar os hambúrgueres e os der a você, ou então, outro alguém pode pegá-los.
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-04.png" class="illustration">
|
||||
|
||||
Então seu caixa / cozinheiro 👨🍳 finalmente volta com seus hambúrgueres, depois de um longo tempo esperando 🕙 por eles em frente ao balcão.
|
||||
Então seu caixa/cozinheiro 👨🍳 finalmente volta com seus hambúrgueres, depois de um longo tempo esperando 🕙 por eles em frente ao balcão.
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-05.png" class="illustration">
|
||||
|
||||
Você pega seus hambúrgueres e vai para a mesa com seu _crush_.
|
||||
|
||||
Vocês comem os hambúrgueres, e o trabalho está terminado. ⏹
|
||||
Vocês apenas os comem, e o trabalho está terminado. ⏹
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-06.png" class="illustration">
|
||||
|
||||
@@ -213,15 +213,15 @@ Belas ilustrações de [Ketrina Thompson](https://www.instagram.com/ketrinadraws
|
||||
|
||||
---
|
||||
|
||||
Nesse cenário dos hambúrgueres paralelos, você é um computador / programa 🤖 com dois processadores (você e seu _crush_), ambos esperando 🕙 e dedicando sua atenção ⏯ "esperando no balcão" 🕙 por um bom tempo.
|
||||
Nesse cenário dos hambúrgueres paralelos, você é um computador / programa 🤖 com dois processadores (você e seu _crush_), ambos esperando 🕙 e dedicando sua atenção ⏯ a "esperar no balcão" 🕙 por um bom tempo.
|
||||
|
||||
A lanchonete paralela tem 8 processadores (caixas / cozinheiros), enquanto a lanchonete dos hambúrgueres concorrentes tinha apenas 2 (um caixa e um cozinheiro).
|
||||
A lanchonete tem 8 processadores (caixas/cozinheiros). Enquanto a lanchonete dos hambúrgueres concorrentes poderia ter apenas 2 (um caixa e um cozinheiro).
|
||||
|
||||
Ainda assim, a experiência final não foi a melhor. 😞
|
||||
|
||||
---
|
||||
|
||||
Essa seria o equivalente paralelo à história dos hambúrgueres. 🍔
|
||||
Essa seria a história equivalente paralela para hambúrgueres. 🍔
|
||||
|
||||
Para um exemplo "mais real", imagine um banco.
|
||||
|
||||
@@ -231,15 +231,15 @@ Todos os caixas fazendo todo o trabalho, um cliente após o outro 👨💼⏯
|
||||
|
||||
E você tinha que esperar 🕙 na fila por um longo tempo ou poderia perder a vez.
|
||||
|
||||
Você provavelmente não gostaria de levar seu _crush_ 😍 com você para um rolezinho no banco 🏦.
|
||||
Você provavelmente não gostaria de levar seu _crush_ 😍 com você para resolver assuntos no banco 🏦.
|
||||
|
||||
### Conclusão dos hambúrgueres { #burger-conclusion }
|
||||
|
||||
Nesse cenário dos "hambúrgueres com seu _crush_", como tem muita espera, faz mais sentido ter um sistema concorrente ⏸🔀⏯.
|
||||
Nesse cenário dos "hambúrgueres de fast food com seu _crush_", como tem muita espera 🕙, faz mais sentido ter um sistema concorrente ⏸🔀⏯.
|
||||
|
||||
Esse é o caso da maioria das aplicações web.
|
||||
|
||||
Muitos, muitos usuários, mas seu servidor está esperando 🕙 pela sua conexão não tão boa enviar suas requisições.
|
||||
Muitos, muitos usuários, mas seu servidor está esperando 🕙 pela conexão não tão boa deles enviar suas requisições.
|
||||
|
||||
E então esperando 🕙 novamente as respostas voltarem.
|
||||
|
||||
@@ -269,11 +269,11 @@ Então, para equilibrar tudo, imagine a seguinte historinha:
|
||||
|
||||
Não há espera 🕙 em lugar algum, apenas um monte de trabalho para ser feito, em múltiplos cômodos da casa.
|
||||
|
||||
Você poderia ter turnos como no exemplo dos hambúrgueres, primeiro a sala de estar, então a cozinha, mas como você não está esperando por nada, apenas limpando e limpando, as chamadas não afetariam em nada.
|
||||
Você poderia ter turnos como no exemplo dos hambúrgueres, primeiro a sala de estar, então a cozinha, mas como você não está esperando 🕙 por nada, apenas limpando e limpando, as chamadas não afetariam em nada.
|
||||
|
||||
Levaria o mesmo tempo para finalizar com ou sem turnos (concorrência) e você teria feito o mesmo tanto de trabalho.
|
||||
|
||||
Mas nesse caso, se você trouxesse os 8 ex-caixas / cozinheiros / agora-faxineiros, e cada um deles (mais você) pudessem dividir a casa para limpá-la, vocês fariam toda a limpeza em **paralelo**, com a ajuda extra, e terminariam muito mais cedo.
|
||||
Mas nesse caso, se você trouxesse os 8 ex-caixas/cozinheiros/agora-faxineiros, e cada um deles (mais você) pudessem dividir a casa para limpá-la, vocês fariam toda a limpeza em **paralelo**, com a ajuda extra, e terminariam muito mais cedo.
|
||||
|
||||
Nesse cenário, cada um dos faxineiros (incluindo você) poderia ser um processador, fazendo a sua parte do trabalho.
|
||||
|
||||
@@ -285,18 +285,18 @@ Exemplos comuns de operações limitadas por CPU são coisas que exigem processa
|
||||
|
||||
Por exemplo:
|
||||
|
||||
* **Processamento de áudio** ou **imagem**
|
||||
* **Visão Computacional**: uma imagem é composta por milhões de pixels, cada pixel tem 3 valores / cores, processar isso normalmente exige alguma computação em todos esses pixels ao mesmo tempo
|
||||
* **Aprendizado de Máquina**: Normalmente exige muita multiplicação de matrizes e vetores. Pense numa grande planilha com números e em multiplicar todos eles juntos e ao mesmo tempo.
|
||||
* **Deep Learning**: Esse é um subcampo do Aprendizado de Máquina, então, o mesmo se aplica. A diferença é que não há apenas uma grande planilha com números para multiplicar, mas um grande conjunto delas, e em muitos casos, você utiliza um processador especial para construir e/ou usar esses modelos.
|
||||
* **Processamento de áudio** ou **imagem**.
|
||||
* **Visão Computacional**: uma imagem é composta por milhões de pixels, cada pixel tem 3 valores / cores, processar isso normalmente exige alguma computação nesses pixels, todos ao mesmo tempo.
|
||||
* **Aprendizado de Máquina**: normalmente exige muita multiplicação de "matrizes" e "vetores". Pense numa grande planilha com números e em multiplicar todos eles juntos e ao mesmo tempo.
|
||||
* **Deep Learning**: esse é um subcampo do Aprendizado de Máquina, então, o mesmo se aplica. A diferença é que não há apenas uma planilha com números para multiplicar, mas um grande conjunto delas, e em muitos casos, você utiliza um processador especial para construir e / ou usar esses modelos.
|
||||
|
||||
### Concorrência + Paralelismo: Web + Aprendizado de Máquina { #concurrency-parallelism-web-machine-learning }
|
||||
|
||||
Com **FastAPI** você pode levar a vantagem da concorrência que é muito comum para desenvolvimento web (o mesmo atrativo de NodeJS).
|
||||
|
||||
Mas você também pode explorar os benefícios do paralelismo e multiprocessamento (tendo múltiplos processadores rodando em paralelo) para trabalhos **limitados por CPU** como aqueles em sistemas de Aprendizado de Máquina.
|
||||
Mas você também pode explorar os benefícios do paralelismo e multiprocessamento (tendo múltiplos processos rodando em paralelo) para trabalhos **limitados por CPU** como aqueles em sistemas de Aprendizado de Máquina.
|
||||
|
||||
Isso, somado ao simples fato que Python é a principal linguagem para **Data Science**, Aprendizado de Máquina e especialmente Deep Learning, faz do FastAPI uma ótima escolha para APIs web e aplicações com Data Science / Aprendizado de Máquina (entre muitas outras).
|
||||
Isso, somado ao simples fato que Python é a principal linguagem para **Data Science**, Aprendizado de Máquina e especialmente Deep Learning, faz do FastAPI uma ótima escolha para APIs web e aplicações de Data Science / Aprendizado de Máquina (entre muitas outras).
|
||||
|
||||
Para ver como alcançar esse paralelismo em produção veja a seção sobre [Implantação](deployment/index.md).
|
||||
|
||||
@@ -340,7 +340,7 @@ burgers = get_burgers(2)
|
||||
|
||||
---
|
||||
|
||||
Então, se você está usando uma biblioteca que diz que você pode chamá-la com `await`, você precisa criar as *funções de operação de rota* com `async def`, como em:
|
||||
Então, se você está usando uma biblioteca que diz que você pode chamá-la com `await`, você precisa criar as *funções de operação de rota* que a utilizam com `async def`, como em:
|
||||
|
||||
```Python hl_lines="2-3"
|
||||
@app.get('/burgers')
|
||||
@@ -355,9 +355,9 @@ Você deve ter observado que `await` pode ser usado somente dentro de funções
|
||||
|
||||
Mas ao mesmo tempo, funções definidas com `async def` têm que ser "aguardadas". Então, funções com `async def` podem ser chamadas somente dentro de funções definidas com `async def` também.
|
||||
|
||||
Então, sobre o ovo e a galinha, como você chama a primeira função async?
|
||||
Então, sobre o ovo e a galinha, como você chama a primeira função `async`?
|
||||
|
||||
Se você estivar trabalhando com **FastAPI** não terá que se preocupar com isso, porquê essa "primeira" função será a sua *função de operação de rota*, e o FastAPI saberá como fazer a coisa certa.
|
||||
Se você estiver trabalhando com **FastAPI** não terá que se preocupar com isso, porquê essa "primeira" função será a sua *função de operação de rota*, e o FastAPI saberá como fazer a coisa certa.
|
||||
|
||||
Mas se você quiser usar `async` / `await` sem FastAPI, você também pode fazê-lo.
|
||||
|
||||
@@ -423,7 +423,7 @@ Ainda, em ambas as situações, as chances são que o **FastAPI** [ainda será m
|
||||
|
||||
### Dependências { #dependencies }
|
||||
|
||||
O mesmo se aplica para as [dependências](tutorial/dependencies/index.md). Se uma dependência tem as funções com padrão `def` ao invés de `async def`, ela é rodada no threadpool externo.
|
||||
O mesmo se aplica para as [dependências](tutorial/dependencies/index.md). Se uma dependência é uma função `def` padrão ao invés de `async def`, ela é rodada no threadpool externo.
|
||||
|
||||
### Sub-dependências { #sub-dependencies }
|
||||
|
||||
@@ -435,7 +435,7 @@ Qualquer outra função de utilidade que você chame diretamente pode ser criada
|
||||
|
||||
Isso está em contraste às funções que o FastAPI chama para você: *funções de operação de rota* e dependências.
|
||||
|
||||
Se sua função de utilidade é uma função normal com `def`, ela será chamada diretamente (como você a escreve no código), não em uma threadpool, se a função é criada com `async def` então você deve esperar por essa função quando você chamá-la no seu código.
|
||||
Se sua função de utilidade é uma função normal com `def`, ela será chamada diretamente (como você a escreve no código), não em uma threadpool, se a função é criada com `async def` então você deveria usar `await` nessa função quando você chamá-la no seu código.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ FastAPI Cloud é o patrocinador principal e provedor de financiamento dos projet
|
||||
|
||||
## Provedores de Nuvem - Patrocinadores { #cloud-providers-sponsors }
|
||||
|
||||
Alguns outros provedores de nuvem ✨ [**patrocinam o FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ também. 🙇
|
||||
Alguns outros provedores de nuvem ✨ [**patrocinam o FastAPI**](https://github.com/sponsors/tiangolo) ✨ também. 🙇
|
||||
|
||||
Você também pode considerá-los para seguir seus tutoriais e experimentar seus serviços:
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Conceitos de Implantações { #deployments-concepts }
|
||||
|
||||
Ao implantar um aplicativo **FastAPI**, ou na verdade, qualquer tipo de API da web, há vários conceitos com os quais você provavelmente se importa e, usando-os, você pode encontrar a maneira **mais apropriada** de **implantar seu aplicativo**.
|
||||
Ao implantar uma aplicação **FastAPI**, ou na verdade, qualquer tipo de API da web, há vários conceitos com os quais você provavelmente se importa e, usando-os, você pode encontrar a maneira **mais apropriada** de **implantar sua aplicação**.
|
||||
|
||||
Alguns dos conceitos importantes são:
|
||||
|
||||
@@ -19,7 +19,7 @@ Vou lhe contar um pouco mais sobre esses **conceitos** aqui, e espero que isso l
|
||||
|
||||
Ao considerar esses conceitos, você será capaz de **avaliar e projetar** a melhor maneira de implantar **suas próprias APIs**.
|
||||
|
||||
Nos próximos capítulos, darei a você mais **receitas concretas** para implantar aplicativos FastAPI.
|
||||
Nos próximos capítulos, darei a você mais **receitas concretas** para implantar aplicações FastAPI.
|
||||
|
||||
Mas por enquanto, vamos verificar essas importantes **ideias conceituais**. Esses conceitos também se aplicam a qualquer outro tipo de API da web. 💡
|
||||
|
||||
@@ -27,7 +27,7 @@ Mas por enquanto, vamos verificar essas importantes **ideias conceituais**. Esse
|
||||
|
||||
No [capítulo anterior sobre HTTPS](https.md) aprendemos como o HTTPS fornece criptografia para sua API.
|
||||
|
||||
Também vimos que o HTTPS normalmente é fornecido por um componente **externo** ao seu servidor de aplicativos, um **Proxy de terminação TLS**.
|
||||
Também vimos que o HTTPS normalmente é fornecido por um componente **externo** ao seu servidor de aplicações, um **Proxy de terminação TLS**.
|
||||
|
||||
E tem que haver algo responsável por **renovar os certificados HTTPS**, pode ser o mesmo componente ou pode ser algo diferente.
|
||||
|
||||
@@ -75,7 +75,7 @@ A palavra **processo** normalmente é usada de forma mais específica, referindo
|
||||
* Isso não se refere ao arquivo, nem ao código, refere-se **especificamente** à coisa que está sendo **executada** e gerenciada pelo sistema operacional.
|
||||
* Qualquer programa, qualquer código, **só pode fazer coisas** quando está sendo **executado**. Então, quando há um **processo em execução**.
|
||||
* O processo pode ser **terminado** (ou "morto") por você, ou pelo sistema operacional. Nesse ponto, ele para de rodar/ser executado, e ele **não pode mais fazer coisas**.
|
||||
* Cada aplicativo que você tem em execução no seu computador tem algum processo por trás dele, cada programa em execução, cada janela, etc. E normalmente há muitos processos em execução **ao mesmo tempo** enquanto um computador está ligado.
|
||||
* Cada aplicação que você tem em execução no seu computador tem algum processo por trás dela, cada programa em execução, cada janela, etc. E normalmente há muitos processos em execução **ao mesmo tempo** enquanto um computador está ligado.
|
||||
* Pode haver **vários processos** do **mesmo programa** em execução ao mesmo tempo.
|
||||
|
||||
Se você verificar o "gerenciador de tarefas" ou o "monitor do sistema" (ou ferramentas semelhantes) no seu sistema operacional, poderá ver muitos desses processos em execução.
|
||||
@@ -104,11 +104,11 @@ E se o servidor for reiniciado (por exemplo, após atualizações ou migrações
|
||||
|
||||
### Executar automaticamente na inicialização { #run-automatically-on-startup }
|
||||
|
||||
Em geral, você provavelmente desejará que o programa do servidor (por exemplo, Uvicorn) seja iniciado automaticamente na inicialização do servidor e, sem precisar de nenhuma **intervenção humana**, tenha um processo sempre em execução com sua API (por exemplo, Uvicorn executando seu aplicativo FastAPI).
|
||||
Em geral, você provavelmente desejará que o programa do servidor (por exemplo, Uvicorn) seja iniciado automaticamente na inicialização do servidor e, sem precisar de nenhuma **intervenção humana**, tenha um processo sempre em execução com sua API (por exemplo, Uvicorn executando sua aplicação FastAPI).
|
||||
|
||||
### Programa separado { #separate-program }
|
||||
|
||||
Para conseguir isso, você normalmente terá um **programa separado** que garantiria que seu aplicativo fosse executado na inicialização. E em muitos casos, ele também garantiria que outros componentes ou aplicativos também fossem executados, por exemplo, um banco de dados.
|
||||
Para conseguir isso, você normalmente terá um **programa separado** que garantiria que sua aplicação fosse executada na inicialização. E em muitos casos, ele também garantiria que outros componentes ou aplicações também fossem executados, por exemplo, um banco de dados.
|
||||
|
||||
### Ferramentas de exemplo para executar na inicialização { #example-tools-to-run-at-startup }
|
||||
|
||||
@@ -127,7 +127,7 @@ Darei exemplos mais concretos nos próximos capítulos.
|
||||
|
||||
## Reinicializações { #restarts }
|
||||
|
||||
Semelhante a garantir que seu aplicativo seja executado na inicialização, você provavelmente também deseja garantir que ele seja **reiniciado** após falhas.
|
||||
Semelhante a garantir que sua aplicação seja executada na inicialização, você provavelmente também deseja garantir que ela seja **reiniciada** após falhas.
|
||||
|
||||
### Nós cometemos erros { #we-make-mistakes }
|
||||
|
||||
@@ -137,15 +137,15 @@ E nós, como desenvolvedores, continuamos aprimorando o código à medida que en
|
||||
|
||||
### Pequenos erros são tratados automaticamente { #small-errors-automatically-handled }
|
||||
|
||||
Ao criar APIs da web com FastAPI, se houver um erro em nosso código, o FastAPI normalmente o conterá na única solicitação que acionou o erro. 🛡
|
||||
Ao criar APIs da web com FastAPI, se houver um erro em nosso código, o FastAPI normalmente o conterá na única request que acionou o erro. 🛡
|
||||
|
||||
O cliente receberá um **Erro Interno do Servidor 500** para essa solicitação, mas o aplicativo continuará funcionando para as próximas solicitações em vez de travar completamente.
|
||||
O cliente receberá um **Erro Interno do Servidor 500** para essa request, mas a aplicação continuará funcionando para as próximas requests em vez de travar completamente.
|
||||
|
||||
### Erros maiores - Travamentos { #bigger-errors-crashes }
|
||||
|
||||
No entanto, pode haver casos em que escrevemos algum código que **trava todo o aplicativo**, fazendo com que o Uvicorn e o Python travem. 💥
|
||||
No entanto, pode haver casos em que escrevemos algum código que **trava toda a aplicação**, fazendo com que o Uvicorn e o Python travem. 💥
|
||||
|
||||
E ainda assim, você provavelmente não gostaria que o aplicativo permanecesse inativo porque houve um erro em um lugar, você provavelmente quer que ele **continue em execução** pelo menos para as *operações de rota* que não estão quebradas.
|
||||
E ainda assim, você provavelmente não gostaria que a aplicação permanecesse inativa porque houve um erro em um lugar, você provavelmente quer que ela **continue em execução** pelo menos para as *operações de rota* que não estão quebradas.
|
||||
|
||||
### Reiniciar após falha { #restart-after-crash }
|
||||
|
||||
@@ -153,13 +153,13 @@ Mas nos casos com erros realmente graves que travam o **processo** em execução
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
...Embora se o aplicativo inteiro estiver **travando imediatamente**, provavelmente não faça sentido reiniciá-lo para sempre. Mas nesses casos, você provavelmente notará isso durante o desenvolvimento, ou pelo menos logo após a implantação.
|
||||
...Embora se a aplicação inteira estiver **travando imediatamente**, provavelmente não faça sentido reiniciá-la para sempre. Mas nesses casos, você provavelmente notará isso durante o desenvolvimento, ou pelo menos logo após a implantação.
|
||||
|
||||
Então, vamos nos concentrar nos casos principais, onde ele pode travar completamente em alguns casos específicos **no futuro**, e ainda faz sentido reiniciá-lo.
|
||||
Então, vamos nos concentrar nos casos principais, onde ela pode travar completamente em alguns casos específicos **no futuro**, e ainda faz sentido reiniciá-la.
|
||||
|
||||
///
|
||||
|
||||
Você provavelmente gostaria de ter a coisa responsável por reiniciar seu aplicativo como um **componente externo**, porque a essa altura, o mesmo aplicativo com Uvicorn e Python já havia travado, então não há nada no mesmo código do mesmo aplicativo que possa fazer algo a respeito.
|
||||
Você provavelmente gostaria de ter a coisa responsável por reiniciar sua aplicação como um **componente externo**, porque a essa altura, a mesma aplicação com Uvicorn e Python já havia travado, então não há nada no mesmo código da mesma aplicação que possa fazer algo a respeito.
|
||||
|
||||
### Ferramentas de exemplo para reiniciar automaticamente { #example-tools-to-restart-automatically }
|
||||
|
||||
@@ -178,13 +178,13 @@ Por exemplo, isso poderia ser resolvido por:
|
||||
|
||||
## Replicação - Processos e Memória { #replication-processes-and-memory }
|
||||
|
||||
Com um aplicativo FastAPI, usando um programa de servidor como o comando `fastapi` que executa o Uvicorn, executá-lo uma vez em **um processo** pode atender a vários clientes simultaneamente.
|
||||
Com uma aplicação FastAPI, usando um programa de servidor como o comando `fastapi` que executa o Uvicorn, executá-lo uma vez em **um processo** pode atender a vários clientes simultaneamente.
|
||||
|
||||
Mas em muitos casos, você desejará executar vários processos de trabalho ao mesmo tempo.
|
||||
|
||||
### Processos Múltiplos - Trabalhadores { #multiple-processes-workers }
|
||||
|
||||
Se você tiver mais clientes do que um único processo pode manipular (por exemplo, se a máquina virtual não for muito grande) e tiver **vários núcleos** na CPU do servidor, você poderá ter **vários processos** em execução com o mesmo aplicativo ao mesmo tempo e distribuir todas as solicitações entre eles.
|
||||
Se você tiver mais clientes do que um único processo pode manipular (por exemplo, se a máquina virtual não for muito grande) e tiver **vários núcleos** na CPU do servidor, você poderá ter **vários processos** em execução com a mesma aplicação ao mesmo tempo e distribuir todas as requests entre eles.
|
||||
|
||||
Quando você executa **vários processos** do mesmo programa de API, eles são comumente chamados de **trabalhadores**.
|
||||
|
||||
@@ -214,11 +214,11 @@ Neste exemplo, há um **Processo Gerenciador** que inicia e controla dois **Proc
|
||||
|
||||
Este Processo de Gerenciador provavelmente seria o que escutaria na **porta** no IP. E ele transmitiria toda a comunicação para os processos de trabalho.
|
||||
|
||||
Esses processos de trabalho seriam aqueles que executariam seu aplicativo, eles executariam os cálculos principais para receber uma **solicitação** e retornar uma **resposta**, e carregariam qualquer coisa que você colocasse em variáveis na RAM.
|
||||
Esses processos de trabalho seriam aqueles que executariam sua aplicação, eles executariam os cálculos principais para receber uma **request** e retornar uma **resposta**, e carregariam qualquer coisa que você colocasse em variáveis na RAM.
|
||||
|
||||
<img src="/img/deployment/concepts/process-ram.drawio.svg">
|
||||
|
||||
E, claro, a mesma máquina provavelmente teria **outros processos** em execução, além do seu aplicativo.
|
||||
E, claro, a mesma máquina provavelmente teria **outros processos** em execução, além da sua aplicação.
|
||||
|
||||
Um detalhe interessante é que a porcentagem da **CPU usada** por cada processo pode **variar** muito ao longo do tempo, mas a **memória (RAM)** normalmente fica mais ou menos **estável**.
|
||||
|
||||
@@ -255,9 +255,9 @@ Por exemplo, você pode querer executar **migrações de banco de dados**.
|
||||
|
||||
Mas na maioria dos casos, você precisará executar essas etapas apenas **uma vez**.
|
||||
|
||||
Portanto, você vai querer ter um **processo único** para executar essas **etapas anteriores** antes de iniciar o aplicativo.
|
||||
Portanto, você vai querer ter um **processo único** para executar essas **etapas anteriores** antes de iniciar a aplicação.
|
||||
|
||||
E você terá que se certificar de que é um único processo executando essas etapas anteriores *mesmo* se depois, você iniciar **vários processos** (vários trabalhadores) para o próprio aplicativo. Se essas etapas fossem executadas por **vários processos**, eles **duplicariam** o trabalho executando-o em **paralelo**, e se as etapas fossem algo delicado como uma migração de banco de dados, elas poderiam causar conflitos entre si.
|
||||
E você terá que se certificar de que é um único processo executando essas etapas anteriores *mesmo* se depois, você iniciar **vários processos** (vários trabalhadores) para a própria aplicação. Se essas etapas fossem executadas por **vários processos**, eles **duplicariam** o trabalho executando-o em **paralelo**, e se as etapas fossem algo delicado como uma migração de banco de dados, elas poderiam causar conflitos entre si.
|
||||
|
||||
Claro, há alguns casos em que não há problema em executar as etapas anteriores várias vezes; nesse caso, é muito mais fácil de lidar.
|
||||
|
||||
@@ -276,7 +276,7 @@ Isso **dependerá muito** da maneira como você **implanta seu sistema** e prova
|
||||
Aqui estão algumas ideias possíveis:
|
||||
|
||||
* Um "Init Container" no Kubernetes que roda antes do seu app container
|
||||
* Um script bash que roda os passos anteriores e então inicia seu aplicativo
|
||||
* Um script bash que roda os passos anteriores e então inicia sua aplicação
|
||||
* Você ainda precisaria de uma maneira de iniciar/reiniciar *aquele* script bash, detectar erros, etc.
|
||||
|
||||
/// tip | Dica
|
||||
@@ -307,7 +307,7 @@ Você pode usar ferramentas simples como `htop` para ver a CPU e a RAM usadas no
|
||||
|
||||
## Recapitular { #recap }
|
||||
|
||||
Você leu aqui alguns dos principais conceitos que provavelmente precisa ter em mente ao decidir como implantar seu aplicativo:
|
||||
Você leu aqui alguns dos principais conceitos que provavelmente precisa ter em mente ao decidir como implantar sua aplicação:
|
||||
|
||||
* Segurança - HTTPS
|
||||
* Executando na inicialização
|
||||
|
||||
@@ -50,7 +50,7 @@ Uma imagem de contêiner é uma versão **estática** de todos os arquivos, vari
|
||||
|
||||
Em contraste com a "**imagem de contêiner**" que contém os conteúdos estáticos armazenados, um "**contêiner**" normalmente se refere à instância rodando, a coisa que está sendo **executada**.
|
||||
|
||||
Quando o **contêiner** é iniciado e está rodando (iniciado a partir de uma **imagem de contêiner**), ele pode criar ou modificar arquivos, variáveis de ambiente, etc. Essas mudanças vão existir somente nesse contêiner, mas não persistirão na imagem subjacente do container (não serão salvas no disco).
|
||||
Quando o **contêiner** é iniciado e está rodando (iniciado a partir de uma **imagem de contêiner**), ele pode criar ou modificar arquivos, variáveis de ambiente, etc. Essas mudanças vão existir somente nesse contêiner, mas não persistirão na imagem subjacente do contêiner (não serão salvas no disco).
|
||||
|
||||
Uma imagem de contêiner é comparável ao arquivo de **programa** e seus conteúdos, ex.: `python` e algum arquivo `main.py`.
|
||||
|
||||
@@ -64,7 +64,7 @@ E existe um [Docker Hub](https://hub.docker.com/) público com **imagens de cont
|
||||
|
||||
Por exemplo, há uma [Imagem Python](https://hub.docker.com/_/python) oficial.
|
||||
|
||||
E existe muitas outras imagens para diferentes coisas, como bancos de dados, por exemplo:
|
||||
E existem muitas outras imagens para diferentes coisas, como bancos de dados, por exemplo:
|
||||
|
||||
* [PostgreSQL](https://hub.docker.com/_/postgres)
|
||||
* [MySQL](https://hub.docker.com/_/mysql)
|
||||
@@ -87,11 +87,11 @@ Quando um **contêiner** é iniciado, ele irá rodar esse comando/programa (embo
|
||||
|
||||
Um contêiner está rodando enquanto o **processo principal** (comando ou programa) estiver rodando.
|
||||
|
||||
Um contêiner normalmente tem um **único processo**, mas também é possível iniciar sub-processos a partir do processo principal, e dessa forma você terá **vários processos** no mesmo contêiner.
|
||||
Um contêiner normalmente tem um **único processo**, mas também é possível iniciar subprocessos a partir do processo principal, e dessa forma você terá **vários processos** no mesmo contêiner.
|
||||
|
||||
Mas não é possível ter um contêiner rodando sem **pelo menos um processo rodando**. Se o processo principal parar, o contêiner também para.
|
||||
|
||||
## Construir uma Imagem Docker para FastAPI { #build-a-docker-image-for-fastapi }
|
||||
## Construa uma Imagem Docker para FastAPI { #build-a-docker-image-for-fastapi }
|
||||
|
||||
Okay, vamos construir algo agora! 🚀
|
||||
|
||||
@@ -132,7 +132,7 @@ Successfully installed fastapi pydantic
|
||||
|
||||
</div>
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Há outros formatos e ferramentas para definir e instalar dependências de pacotes.
|
||||
|
||||
@@ -262,7 +262,7 @@ Isso pode ser bem perceptível ao usar `docker compose`. Veja esta seção de FA
|
||||
|
||||
#### Estrutura de diretórios { #directory-structure }
|
||||
|
||||
Agora você deve haver uma estrutura de diretório como:
|
||||
Agora você deveria ter uma estrutura de diretório como:
|
||||
|
||||
```
|
||||
.
|
||||
@@ -275,7 +275,7 @@ Agora você deve haver uma estrutura de diretório como:
|
||||
|
||||
#### Por trás de um Proxy de Terminação TLS { #behind-a-tls-termination-proxy }
|
||||
|
||||
Se você está executando seu contêiner atrás de um Proxy de Terminação TLS (load balancer) como Nginx ou Traefik, adicione a opção `--proxy-headers`, isso fará com que o Uvicorn (pela CLI do FastAPI) confie nos cabeçalhos enviados por esse proxy, informando que o aplicativo está sendo executado atrás do HTTPS, etc.
|
||||
Se você está executando seu contêiner atrás de um Proxy de Terminação TLS (balanceador de carga) como Nginx ou Traefik, adicione a opção `--proxy-headers`, isso fará com que o Uvicorn (pela CLI do FastAPI) confie nos cabeçalhos enviados por esse proxy, informando que o aplicativo está sendo executado atrás do HTTPS, etc.
|
||||
|
||||
```Dockerfile
|
||||
CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
|
||||
@@ -289,7 +289,7 @@ Existe um truque importante nesse `Dockerfile`, primeiro copiamos o **arquivo co
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
```
|
||||
|
||||
Docker e outras ferramentas **constróem** essas imagens de contêiner **incrementalmente**, adicionando **uma camada em cima da outra**, começando do topo do `Dockerfile` e adicionando qualquer arquivo criado por cada uma das instruções do `Dockerfile`.
|
||||
Docker e outras ferramentas **constroem** essas imagens de contêiner **incrementalmente**, adicionando **uma camada em cima da outra**, começando do topo do `Dockerfile` e adicionando qualquer arquivo criado por cada uma das instruções do `Dockerfile`.
|
||||
|
||||
Docker e ferramentas similares também usam um **cache interno** ao construir a imagem, se um arquivo não mudou desde a última vez que a imagem do contêiner foi construída, então ele irá **reutilizar a mesma camada** criada na última vez, ao invés de copiar o arquivo novamente e criar uma nova camada do zero.
|
||||
|
||||
@@ -352,7 +352,7 @@ $ docker run -d --name mycontainer -p 80:80 myimage
|
||||
|
||||
## Verifique { #check-it }
|
||||
|
||||
Você deve ser capaz de verificar isso no URL do seu contêiner Docker, por exemplo: [http://192.168.99.100/items/5?q=somequery](http://192.168.99.100/items/5?q=somequery) ou [http://127.0.0.1/items/5?q=somequery](http://127.0.0.1/items/5?q=somequery) (ou equivalente, usando seu host Docker).
|
||||
Você deveria conseguir verificar isso no URL do seu contêiner Docker, por exemplo: [http://192.168.99.100/items/5?q=somequery](http://192.168.99.100/items/5?q=somequery) ou [http://127.0.0.1/items/5?q=somequery](http://127.0.0.1/items/5?q=somequery) (ou equivalente, usando seu host Docker).
|
||||
|
||||
Você verá algo como:
|
||||
|
||||
@@ -376,9 +376,9 @@ Você verá a documentação alternativa automática (fornecida pelo [ReDoc](htt
|
||||
|
||||

|
||||
|
||||
## Construa uma Imagem Docker com um FastAPI de Arquivo Único { #build-a-docker-image-with-a-single-file-fastapi }
|
||||
## Construa uma Imagem Docker com uma aplicação FastAPI de Arquivo Único { #build-a-docker-image-with-a-single-file-fastapi }
|
||||
|
||||
Se seu FastAPI for um único arquivo, por exemplo, `main.py` sem um diretório `./app`, sua estrutura de arquivos poderia ser assim:
|
||||
Se sua aplicação FastAPI for um único arquivo, por exemplo, `main.py` sem um diretório `./app`, sua estrutura de arquivos poderia ser assim:
|
||||
|
||||
```
|
||||
.
|
||||
@@ -456,7 +456,7 @@ Sem usar contêineres, fazer aplicativos executarem na inicialização e com rei
|
||||
|
||||
Se você tiver um <dfn title="Um grupo de máquinas que são configuradas para estarem conectadas e trabalharem juntas de alguma forma.">cluster</dfn> de máquinas com **Kubernetes**, Docker Swarm Mode, Nomad ou outro sistema complexo semelhante para gerenciar contêineres distribuídos em várias máquinas, então provavelmente desejará **lidar com a replicação** no **nível do cluster** em vez de usar um **gerenciador de processos** (como Uvicorn com workers) em cada contêiner.
|
||||
|
||||
Um desses sistemas de gerenciamento de contêineres distribuídos como o Kubernetes normalmente tem alguma maneira integrada de lidar com a **replicação de contêineres** enquanto ainda oferece **balanceamento de carga** para as solicitações recebidas. Tudo no **nível do cluster**.
|
||||
Um desses sistemas de gerenciamento de contêineres distribuídos como o Kubernetes normalmente tem alguma maneira integrada de lidar com a **replicação de contêineres** enquanto ainda oferece **balanceamento de carga** para os requests recebidos. Tudo no **nível do cluster**.
|
||||
|
||||
Nesses casos, você provavelmente desejará criar uma **imagem Docker do zero** como [explicado acima](#dockerfile), instalando suas dependências e executando **um único processo Uvicorn** em vez de usar múltiplos workers do Uvicorn.
|
||||
|
||||
@@ -464,7 +464,7 @@ Nesses casos, você provavelmente desejará criar uma **imagem Docker do zero**
|
||||
|
||||
Quando usando contêineres, normalmente você terá algum componente **escutando na porta principal**. Poderia ser outro contêiner que também é um **Proxy de Terminação TLS** para lidar com **HTTPS** ou alguma ferramenta semelhante.
|
||||
|
||||
Como esse componente assumiria a **carga** de solicitações e distribuiria isso entre os workers de uma maneira (esperançosamente) **balanceada**, ele também é comumente chamado de **Balanceador de Carga**.
|
||||
Como esse componente assumiria a **carga** de requests e distribuiria isso entre os workers de uma maneira (esperançosamente) **balanceada**, ele também é comumente chamado de **Balanceador de Carga**.
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
@@ -472,17 +472,17 @@ O mesmo componente **Proxy de Terminação TLS** usado para HTTPS provavelmente
|
||||
|
||||
///
|
||||
|
||||
E quando trabalhar com contêineres, o mesmo sistema que você usa para iniciar e gerenciá-los já terá ferramentas internas para transmitir a **comunicação de rede** (por exemplo, solicitações HTTP) do **balanceador de carga** (que também pode ser um **Proxy de Terminação TLS**) para o(s) contêiner(es) com seu aplicativo.
|
||||
E quando trabalhar com contêineres, o mesmo sistema que você usa para iniciar e gerenciá-los já terá ferramentas internas para transmitir a **comunicação de rede** (por exemplo, requests HTTP) do **balanceador de carga** (que também pode ser um **Proxy de Terminação TLS**) para o(s) contêiner(es) com seu aplicativo.
|
||||
|
||||
### Um Balanceador de Carga - Múltiplos Contêineres de Workers { #one-load-balancer-multiple-worker-containers }
|
||||
|
||||
Quando trabalhando com **Kubernetes** ou sistemas similares de gerenciamento de contêiner distribuído, usar seus mecanismos de rede internos permite que o único **balanceador de carga** que está escutando na **porta principal** transmita a comunicação (solicitações) para possivelmente **múltiplos contêineres** executando seu aplicativo.
|
||||
Quando trabalhando com **Kubernetes** ou sistemas similares de gerenciamento de contêiner distribuído, usar seus mecanismos de rede internos permite que o único **balanceador de carga** que está escutando na **porta principal** transmita a comunicação (requests) para possivelmente **múltiplos contêineres** executando seu aplicativo.
|
||||
|
||||
Cada um desses contêineres executando seu aplicativo normalmente teria **apenas um processo** (ex.: um processo Uvicorn executando seu aplicativo FastAPI). Todos seriam **contêineres idênticos**, executando a mesma coisa, mas cada um com seu próprio processo, memória, etc. Dessa forma, você aproveitaria a **paralelização** em **núcleos diferentes** da CPU, ou até mesmo em **máquinas diferentes**.
|
||||
|
||||
E o sistema de contêiner com o **balanceador de carga** iria **distribuir as solicitações** para cada um dos contêineres com seu aplicativo **em turnos**. Portanto, cada solicitação poderia ser tratada por um dos múltiplos **contêineres replicados** executando seu aplicativo.
|
||||
E o sistema de contêiner com o **balanceador de carga** iria **distribuir os requests** para cada um dos contêineres com seu aplicativo **em turnos**. Portanto, cada request poderia ser tratado por um dos múltiplos **contêineres replicados** executando seu aplicativo.
|
||||
|
||||
E normalmente esse **balanceador de carga** seria capaz de lidar com solicitações que vão para *outros* aplicativos em seu cluster (por exemplo, para um domínio diferente, ou sob um prefixo de URL diferente), e transmitiria essa comunicação para os contêineres certos para *esse outro* aplicativo em execução em seu cluster.
|
||||
E normalmente esse **balanceador de carga** seria capaz de lidar com requests que vão para *outros* aplicativos em seu cluster (por exemplo, para um domínio diferente, ou sob um prefixo de path de URL diferente), e transmitiria essa comunicação para os contêineres certos para *esse outro* aplicativo em execução em seu cluster.
|
||||
|
||||
### Um Processo por Contêiner { #one-process-per-container }
|
||||
|
||||
@@ -544,7 +544,7 @@ Se você executar **um único processo por contêiner**, terá uma quantidade ma
|
||||
|
||||
E então você pode definir esses mesmos limites e requisitos de memória em suas configurações para seu sistema de gerenciamento de contêineres (por exemplo, no **Kubernetes**). Dessa forma, ele poderá **replicar os contêineres** nas **máquinas disponíveis** levando em consideração a quantidade de memória necessária por eles e a quantidade disponível nas máquinas no cluster.
|
||||
|
||||
Se sua aplicação for **simples**, isso provavelmente **não será um problema**, e você pode não precisar especificar limites de memória rígidos. Mas se você estiver **usando muita memória** (por exemplo, com **modelos de aprendizado de máquina**), deve verificar quanta memória está consumindo e ajustar o **número de contêineres** que executa em **cada máquina** (e talvez adicionar mais máquinas ao seu cluster).
|
||||
Se sua aplicação for **simples**, isso provavelmente **não será um problema**, e você pode não precisar especificar limites de memória rígidos. Mas se você estiver **usando muita memória** (por exemplo, com modelos de **Aprendizado de Máquina**), você deveria verificar quanta memória está consumindo e ajustar o **número de contêineres** que executa em **cada máquina** (e talvez adicionar mais máquinas ao seu cluster).
|
||||
|
||||
Se você executar **múltiplos processos por contêiner**, deve garantir que o número de processos iniciados não **consuma mais memória** do que o disponível.
|
||||
|
||||
@@ -556,7 +556,7 @@ Se você estiver usando contêineres (por exemplo, Docker, Kubernetes), existem
|
||||
|
||||
Se você tiver **múltiplos contêineres**, provavelmente cada um executando um **único processo** (por exemplo, em um cluster do **Kubernetes**), então provavelmente você gostaria de ter um **contêiner separado** fazendo o trabalho dos **passos anteriores** em um único contêiner, executando um único processo, **antes** de executar os contêineres workers replicados.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Se você estiver usando o Kubernetes, provavelmente será um [Init Container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/).
|
||||
|
||||
@@ -572,7 +572,7 @@ Se você tiver uma configuração simples, com um **único contêiner** que ent
|
||||
|
||||
Antes havia uma imagem oficial do FastAPI para Docker: [tiangolo/uvicorn-gunicorn-fastapi](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker). Mas agora ela está descontinuada. ⛔️
|
||||
|
||||
Você provavelmente **não** deve usar essa imagem base do Docker (ou qualquer outra semelhante).
|
||||
Você provavelmente **não** deveria usar essa imagem base do Docker (ou qualquer outra semelhante).
|
||||
|
||||
Se você está usando **Kubernetes** (ou outros) e já está definindo a **replicação** no nível do cluster, com vários **contêineres**. Nesses casos, é melhor **construir uma imagem do zero** como descrito acima: [Construir uma Imagem Docker para FastAPI](#build-a-docker-image-for-fastapi).
|
||||
|
||||
|
||||
@@ -1,26 +1,6 @@
|
||||
# FastAPI Cloud { #fastapi-cloud }
|
||||
|
||||
Você pode implantar sua aplicação FastAPI no [FastAPI Cloud](https://fastapicloud.com) com um **único comando**; entre na lista de espera, caso ainda não tenha feito isso. 🚀
|
||||
|
||||
## Login { #login }
|
||||
|
||||
Certifique-se de que você já tem uma conta no **FastAPI Cloud** (nós convidamos você a partir da lista de espera 😉).
|
||||
|
||||
Depois, faça login:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi login
|
||||
|
||||
You are logged in to FastAPI Cloud 🚀
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Implantar { #deploy }
|
||||
|
||||
Agora, implante sua aplicação, com **um único comando**:
|
||||
Você pode implantar sua aplicação FastAPI no [FastAPI Cloud](https://fastapicloud.com) com apenas **um comando**. 🚀
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -36,6 +16,8 @@ Deploying to FastAPI Cloud...
|
||||
|
||||
</div>
|
||||
|
||||
A CLI detectará automaticamente sua aplicação FastAPI e a implantará na nuvem. Se você não estiver autenticado, seu navegador será aberto para concluir o processo de autenticação.
|
||||
|
||||
É isso! Agora você pode acessar sua aplicação nesse URL. ✨
|
||||
|
||||
## Sobre o FastAPI Cloud { #about-fastapi-cloud }
|
||||
|
||||
@@ -10,31 +10,31 @@ Se você está com pressa ou não se importa, continue com as seções seguintes
|
||||
|
||||
///
|
||||
|
||||
Para aprender o básico de HTTPS do ponto de vista do consumidor, verifique [https://howhttps.works/](https://howhttps.works/).
|
||||
Para **aprender o básico de HTTPS**, do ponto de vista do consumidor, verifique [https://howhttps.works/](https://howhttps.works/).
|
||||
|
||||
Agora, a partir de uma perspectiva do desenvolvedor, aqui estão algumas coisas para ter em mente ao pensar em HTTPS:
|
||||
Agora, a partir de uma **perspectiva do desenvolvedor**, aqui estão algumas coisas para ter em mente ao pensar em HTTPS:
|
||||
|
||||
* Para HTTPS, o servidor precisa ter "certificados" gerados por um terceiro.
|
||||
* Esses certificados são na verdade adquiridos de um terceiro, eles não são simplesmente "gerados".
|
||||
* Certificados têm um tempo de vida.
|
||||
* Eles expiram.
|
||||
* E então eles precisam ser renovados, adquirindo-os novamente de um terceiro.
|
||||
* A criptografia da conexão acontece no nível TCP.
|
||||
* Essa é uma camada abaixo do HTTP.
|
||||
* Portanto, o manuseio do certificado e da criptografia é feito antes do HTTP.
|
||||
* O TCP não sabe sobre "domínios". Apenas sobre endereços IP.
|
||||
* As informações sobre o domínio específico solicitado vão nos dados HTTP.
|
||||
* Os certificados HTTPS “certificam” um determinado domínio, mas o protocolo e a encriptação acontecem ao nível do TCP, antes de sabermos de que domínio se trata.
|
||||
* Por padrão, isso significa que você só pode ter um certificado HTTPS por endereço IP.
|
||||
* Para HTTPS, **o servidor** precisa **ter "certificados"** gerados por um **terceiro**.
|
||||
* Esses certificados são na verdade **adquiridos** de um terceiro, eles não são simplesmente "gerados".
|
||||
* Certificados têm um **tempo de vida**.
|
||||
* Eles **expiram**.
|
||||
* E então eles precisam ser **renovados**, **adquiridos novamente** de um terceiro.
|
||||
* A criptografia da conexão acontece no **nível TCP**.
|
||||
* Essa é uma camada **abaixo do HTTP**.
|
||||
* Portanto, o manuseio do **certificado e da criptografia** é feito **antes do HTTP**.
|
||||
* **O TCP não sabe sobre "domínios"**. Apenas sobre endereços IP.
|
||||
* As informações sobre o **domínio específico** solicitado vão nos **dados HTTP**.
|
||||
* Os **certificados HTTPS** “certificam” um **determinado domínio**, mas o protocolo e a encriptação acontecem ao nível do TCP, **antes de sabermos** de que domínio se trata.
|
||||
* **Por padrão**, isso significa que você só pode ter **um certificado HTTPS por endereço IP**.
|
||||
* Não importa o tamanho do seu servidor ou quão pequeno cada aplicativo que você tem nele possa ser.
|
||||
* No entanto, existe uma solução para isso.
|
||||
* Há uma extensão para o protocolo TLS (aquele que lida com a criptografia no nível TCP, antes do HTTP) chamada [<abbr title="Server Name Indication - Indicação do Nome do Servidor">SNI</abbr>](https://en.wikipedia.org/wiki/Server_Name_Indication).
|
||||
* Esta extensão SNI permite que um único servidor (com um único endereço IP) tenha vários certificados HTTPS e atenda a vários domínios / aplicativos HTTPS.
|
||||
* Para que isso funcione, um único componente (programa) em execução no servidor, ouvindo no endereço IP público, deve ter todos os certificados HTTPS no servidor.
|
||||
* Depois de obter uma conexão segura, o protocolo de comunicação ainda é HTTP.
|
||||
* Os conteúdos são criptografados, embora sejam enviados com o protocolo HTTP.
|
||||
* No entanto, existe uma **solução** para isso.
|
||||
* Há uma **extensão** para o protocolo **TLS** (aquele que lida com a criptografia no nível TCP, antes do HTTP) chamada **[<abbr title="Server Name Indication - Indicação do Nome do Servidor">SNI</abbr>](https://en.wikipedia.org/wiki/Server_Name_Indication)**.
|
||||
* Esta extensão SNI permite que um único servidor (com um **único endereço IP**) tenha **vários certificados HTTPS** e atenda a **vários domínios / aplicativos HTTPS**.
|
||||
* Para que isso funcione, um **único** componente (programa) em execução no servidor, ouvindo no **endereço IP público**, deve ter **todos os certificados HTTPS** no servidor.
|
||||
* **Depois** de obter uma conexão segura, o protocolo de comunicação ainda é **HTTP**.
|
||||
* Os conteúdos são **criptografados**, embora sejam enviados com o **protocolo HTTP**.
|
||||
|
||||
É uma prática comum ter um programa/servidor HTTP em execução no servidor (máquina, host, etc.) e gerenciar todas as partes HTTPS: recebendo as requisições HTTPS encriptadas, enviando as solicitações HTTP descriptografadas para o aplicativo HTTP real em execução no mesmo servidor (a aplicação FastAPI, neste caso), pegar a resposta HTTP do aplicativo, criptografá-la usando o certificado HTTPS apropriado e enviá-la de volta ao cliente usando HTTPS. Este servidor é frequentemente chamado de [Proxy de Terminação TLS](https://en.wikipedia.org/wiki/TLS_termination_proxy).
|
||||
É uma prática comum ter **um programa/servidor HTTP** em execução no servidor (máquina, host, etc.) e **gerenciar todas as partes HTTPS**: recebendo as **requisições HTTPS encriptadas**, enviando as **solicitações HTTP descriptografadas** para o aplicativo HTTP real em execução no mesmo servidor (a aplicação **FastAPI**, neste caso), pegar a **resposta HTTP** do aplicativo, **criptografá-la** usando o **certificado HTTPS** apropriado e enviá-la de volta ao cliente usando **HTTPS**. Este servidor é frequentemente chamado de **[Proxy de Terminação TLS](https://en.wikipedia.org/wiki/TLS_termination_proxy)**.
|
||||
|
||||
Algumas das opções que você pode usar como Proxy de Terminação TLS são:
|
||||
|
||||
@@ -45,17 +45,17 @@ Algumas das opções que você pode usar como Proxy de Terminação TLS são:
|
||||
|
||||
## Let's Encrypt { #lets-encrypt }
|
||||
|
||||
Antes de Let's Encrypt, esses certificados HTTPS eram vendidos por terceiros confiáveis.
|
||||
Antes de Let's Encrypt, esses **certificados HTTPS** eram vendidos por terceiros confiáveis.
|
||||
|
||||
O processo de aquisição de um desses certificados costumava ser complicado, exigia bastante papelada e os certificados eram bastante caros.
|
||||
|
||||
Mas então o [Let's Encrypt](https://letsencrypt.org/) foi criado.
|
||||
Mas então o **[Let's Encrypt](https://letsencrypt.org/)** foi criado.
|
||||
|
||||
Ele é um projeto da Linux Foundation que fornece certificados HTTPS gratuitamente. De forma automatizada. Esses certificados usam toda a segurança criptográfica padrão e têm vida curta (cerca de 3 meses), então a segurança é, na verdade, melhor por causa do seu lifespan reduzido.
|
||||
Ele é um projeto da Linux Foundation. Ele fornece **certificados HTTPS gratuitamente**, de forma automatizada. Esses certificados usam toda a segurança criptográfica padrão e têm vida curta (cerca de 3 meses), então a **segurança é, na verdade, melhor** por causa do seu lifespan reduzido.
|
||||
|
||||
Os domínios são verificados com segurança e os certificados são gerados automaticamente. Isso também permite automatizar a renovação desses certificados.
|
||||
|
||||
A ideia é automatizar a aquisição e renovação desses certificados, para que você tenha HTTPS seguro, de graça e para sempre.
|
||||
A ideia é automatizar a aquisição e renovação desses certificados, para que você tenha **HTTPS seguro, de graça e para sempre**.
|
||||
|
||||
## HTTPS para Desenvolvedores { #https-for-developers }
|
||||
|
||||
@@ -63,11 +63,11 @@ Aqui está um exemplo de como uma API HTTPS poderia ser estruturada, passo a pas
|
||||
|
||||
### Nome do domínio { #domain-name }
|
||||
|
||||
A etapa inicial provavelmente seria adquirir algum nome de domínio. Então, você iria configurá-lo em um servidor DNS (possivelmente no mesmo provedor em nuvem).
|
||||
A etapa inicial provavelmente seria **adquirir** algum **nome de domínio**. Então, você iria configurá-lo em um servidor DNS (possivelmente no mesmo provedor em nuvem).
|
||||
|
||||
Você provavelmente usaria um servidor em nuvem (máquina virtual) ou algo parecido, e ele teria um <dfn title="Não muda ao longo do tempo. Não é dinâmico.">fixo</dfn> Endereço IP público.
|
||||
Você provavelmente usaria um servidor em nuvem (máquina virtual) ou algo parecido, e ele teria um **endereço IP público** <dfn title="Não muda ao longo do tempo. Não é dinâmico.">fixo</dfn>.
|
||||
|
||||
No(s) servidor(es) DNS, você configuraria um registro (um `A record`) para apontar seu domínio para o endereço IP público do seu servidor.
|
||||
No(s) servidor(es) DNS, você configuraria um registro (um "`A record`") para apontar **seu domínio** para o **endereço IP público do seu servidor**.
|
||||
|
||||
Você provavelmente fará isso apenas uma vez, na primeira vez em que tudo estiver sendo configurado.
|
||||
|
||||
@@ -81,120 +81,120 @@ Essa parte do Nome do Domínio se dá muito antes do HTTPS, mas como tudo depend
|
||||
|
||||
Agora vamos focar em todas as partes que realmente fazem parte do HTTPS.
|
||||
|
||||
Primeiro, o navegador iria verificar com os servidores DNS qual o IP do domínio, nesse caso, `someapp.example.com`.
|
||||
Primeiro, o navegador iria verificar com os **servidores DNS** qual o **IP do domínio**, nesse caso, `someapp.example.com`.
|
||||
|
||||
Os servidores DNS iriam informar o navegador para utilizar algum endereço IP específico. Esse seria o endereço IP público em uso no seu servidor, que você configurou nos servidores DNS.
|
||||
Os servidores DNS iriam informar o navegador para utilizar algum **endereço IP** específico. Esse seria o endereço IP público em uso no seu servidor, que você configurou nos servidores DNS.
|
||||
|
||||
<img src="/img/deployment/https/https01.drawio.svg">
|
||||
|
||||
### Início do Handshake TLS { #tls-handshake-start }
|
||||
|
||||
O navegador então irá comunicar-se com esse endereço IP na porta 443 (a porta HTTPS).
|
||||
O navegador então irá comunicar-se com esse endereço IP na **porta 443** (a porta HTTPS).
|
||||
|
||||
A primeira parte dessa comunicação é apenas para estabelecer a conexão entre o cliente e o servidor e para decidir as chaves criptográficas a serem utilizadas, etc.
|
||||
|
||||
<img src="/img/deployment/https/https02.drawio.svg">
|
||||
|
||||
Esse interação entre o cliente e o servidor para estabelecer uma conexão TLS é chamada de Handshake TLS.
|
||||
Esse interação entre o cliente e o servidor para estabelecer uma conexão TLS é chamada de **Handshake TLS**.
|
||||
|
||||
### TLS com a Extensão SNI { #tls-with-sni-extension }
|
||||
|
||||
Apenas um processo no servidor pode se conectar a uma porta em um endereço IP. Poderiam existir outros processos conectados em outras portas desse mesmo endereço IP, mas apenas um para cada combinação de endereço IP e porta.
|
||||
**Apenas um processo** no servidor pode se conectar a uma **porta** em um **endereço IP**. Poderiam existir outros processos conectados em outras portas desse mesmo endereço IP, mas apenas um para cada combinação de endereço IP e porta.
|
||||
|
||||
TLS (HTTPS) usa a porta `443` por padrão. Então essa é a porta que precisamos.
|
||||
|
||||
Como apenas um único processo pode se comunicar com essa porta, o processo que faria isso seria o Proxy de Terminação TLS.
|
||||
Como apenas um único processo pode se comunicar com essa porta, o processo que faria isso seria o **Proxy de Terminação TLS**.
|
||||
|
||||
O Proxy de Terminação TLS teria acesso a um ou mais certificados TLS (certificados HTTPS).
|
||||
O Proxy de Terminação TLS teria acesso a um ou mais **certificados TLS** (certificados HTTPS).
|
||||
|
||||
Utilizando a extensão SNI discutida acima, o Proxy de Terminação TLS iria checar qual dos certificados TLS (HTTPS) disponíveis deve ser usado para essa conexão, utilizando o que corresponda ao domínio esperado pelo cliente.
|
||||
Utilizando a **extensão SNI** discutida acima, o Proxy de Terminação TLS iria checar qual dos certificados TLS (HTTPS) disponíveis deve ser usado para essa conexão, utilizando o que corresponda ao domínio esperado pelo cliente.
|
||||
|
||||
Nesse caso, ele usaria o certificado para `someapp.example.com`.
|
||||
|
||||
<img src="/img/deployment/https/https03.drawio.svg">
|
||||
|
||||
O cliente já confia na entidade que gerou o certificado TLS (nesse caso, o Let's Encrypt, mas veremos sobre isso mais tarde), então ele pode verificar que o certificado é válido.
|
||||
O cliente já **confia** na entidade que gerou o certificado TLS (nesse caso, o Let's Encrypt, mas veremos sobre isso mais tarde), então ele pode **verificar** que o certificado é válido.
|
||||
|
||||
Então, utilizando o certificado, o cliente e o Proxy de Terminação TLS decidem como encriptar o resto da comunicação TCP. Isso completa a parte do Handshake TLS.
|
||||
Então, utilizando o certificado, o cliente e o Proxy de Terminação TLS **decidem como encriptar** o resto da **comunicação TCP**. Isso completa a parte do **Handshake TLS**.
|
||||
|
||||
Após isso, o cliente e o servidor possuem uma conexão TCP encriptada, que é provida pelo TLS. E então eles podem usar essa conexão para começar a comunicação HTTP propriamente dita.
|
||||
Após isso, o cliente e o servidor possuem uma **conexão TCP encriptada**, que é provida pelo TLS. E então eles podem usar essa conexão para começar a **comunicação HTTP** propriamente dita.
|
||||
|
||||
E isso resume o que é HTTPS, apenas HTTP simples dentro de uma conexão TLS segura em vez de uma conexão TCP pura (não encriptada).
|
||||
E isso resume o que é **HTTPS**, apenas **HTTP** simples dentro de uma **conexão TLS segura** em vez de uma conexão TCP pura (não encriptada).
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Percebe que a encriptação da comunicação acontece no nível do TCP, não no nível do HTTP.
|
||||
Perceba que a encriptação da comunicação acontece no **nível do TCP**, não no nível do HTTP.
|
||||
|
||||
///
|
||||
|
||||
### Solicitação HTTPS { #https-request }
|
||||
|
||||
Agora que o cliente e servidor (especialmente o navegador e o Proxy de Terminação TLS) possuem uma conexão TCP encriptada, eles podem iniciar a comunicação HTTP.
|
||||
Agora que o cliente e servidor (especialmente o navegador e o Proxy de Terminação TLS) possuem uma **conexão TCP encriptada**, eles podem iniciar a **comunicação HTTP**.
|
||||
|
||||
Então, o cliente envia uma solicitação HTTPS. Que é apenas uma solicitação HTTP sobre uma conexão TLS encriptada.
|
||||
Então, o cliente envia uma **solicitação HTTPS**. Que é apenas uma solicitação HTTP sobre uma conexão TLS encriptada.
|
||||
|
||||
<img src="/img/deployment/https/https04.drawio.svg">
|
||||
|
||||
### Desencripte a Solicitação { #decrypt-the-request }
|
||||
|
||||
O Proxy de Terminação TLS então usaria a encriptação combinada para desencriptar a solicitação, e transmitiria a solicitação básica (desencriptada) para o processo executando a aplicação (por exemplo, um processo com Uvicorn executando a aplicação FastAPI).
|
||||
O Proxy de Terminação TLS então usaria a encriptação combinada para **desencriptar a solicitação**, e transmitiria a **solicitação HTTP básica (desencriptada)** para o processo executando a aplicação (por exemplo, um processo com Uvicorn executando a aplicação FastAPI).
|
||||
|
||||
<img src="/img/deployment/https/https05.drawio.svg">
|
||||
|
||||
### Resposta HTTP { #http-response }
|
||||
|
||||
A aplicação processaria a solicitação e retornaria uma resposta HTTP básica (não encriptada) para o Proxy de Terminação TLS.
|
||||
A aplicação processaria a solicitação e retornaria uma **resposta HTTP básica (não encriptada)** para o Proxy de Terminação TLS.
|
||||
|
||||
<img src="/img/deployment/https/https06.drawio.svg">
|
||||
|
||||
### Resposta HTTPS { #https-response }
|
||||
|
||||
O Proxy de Terminação TLS iria encriptar a resposta utilizando a criptografia combinada anteriormente (que foi definida com o certificado para `someapp.example.com`), e devolveria para o navegador.
|
||||
O Proxy de Terminação TLS iria **encriptar a resposta** utilizando a criptografia combinada anteriormente (que foi definida com o certificado para `someapp.example.com`), e devolveria para o navegador.
|
||||
|
||||
No próximo passo, o navegador verifica que a resposta é válida e encriptada com a chave criptográfica correta, etc. E depois desencripta a resposta e a processa.
|
||||
No próximo passo, o navegador verifica que a resposta é válida e encriptada com a chave criptográfica correta, etc. E depois **desencripta a resposta** e a processa.
|
||||
|
||||
<img src="/img/deployment/https/https07.drawio.svg">
|
||||
|
||||
O cliente (navegador) saberá que a resposta vem do servidor correto por que ela usa a criptografia que foi combinada entre eles usando o certificado HTTPS anterior.
|
||||
O cliente (navegador) saberá que a resposta vem do servidor correto por que ela usa a criptografia que foi combinada entre eles usando o **certificado HTTPS** anterior.
|
||||
|
||||
### Múltiplas Aplicações { #multiple-applications }
|
||||
|
||||
Podem existir múltiplas aplicações em execução no mesmo servidor (ou servidores), por exemplo: outras APIs ou um banco de dados.
|
||||
Podem existir **múltiplas aplicações** em execução no mesmo servidor (ou servidores), por exemplo: outras APIs ou um banco de dados.
|
||||
|
||||
Apenas um processo pode estar vinculado a um IP e porta (o Proxy de Terminação TLS, por exemplo), mas outras aplicações/processos também podem estar em execução no(s) servidor(es), desde que não tentem usar a mesma combinação de IP público e porta.
|
||||
Apenas um processo pode estar vinculado a um IP e porta (o Proxy de Terminação TLS, por exemplo), mas outras aplicações/processos também podem estar em execução no(s) servidor(es), desde que não tentem usar a mesma **combinação de IP público e porta**.
|
||||
|
||||
<img src="/img/deployment/https/https08.drawio.svg">
|
||||
|
||||
Dessa forma, o Proxy de Terminação TLS pode gerenciar o HTTPS e os certificados de múltiplos domínios, para múltiplas aplicações, e então transmitir as requisições para a aplicação correta em cada caso.
|
||||
Dessa forma, o Proxy de Terminação TLS pode gerenciar o HTTPS e os certificados de **múltiplos domínios**, para múltiplas aplicações, e então transmitir as requisições para a aplicação correta em cada caso.
|
||||
|
||||
### Renovação de Certificados { #certificate-renewal }
|
||||
|
||||
Em algum momento futuro, cada certificado irá expirar (aproximadamente 3 meses após a aquisição).
|
||||
Em algum momento futuro, cada certificado irá **expirar** (aproximadamente 3 meses após a aquisição).
|
||||
|
||||
E então, haverá outro programa (em alguns casos pode ser o próprio Proxy de Terminação TLS) que irá interagir com o Let's Encrypt e renovar o(s) certificado(s).
|
||||
E então, haverá outro programa (em alguns casos é outro programa, em alguns casos pode ser o próprio Proxy de Terminação TLS) que irá interagir com o Let's Encrypt e renovar o(s) certificado(s).
|
||||
|
||||
<img src="/img/deployment/https/https.drawio.svg">
|
||||
|
||||
Os certificados TLS são associados com um nome de domínio, e não a um endereço IP.
|
||||
Os **certificados TLS** são **associados com um nome de domínio**, e não a um endereço IP.
|
||||
|
||||
Então para renovar os certificados, o programa de renovação precisa provar para a autoridade (Let's Encrypt) que ele realmente "possui" e controla esse domínio.
|
||||
Então para renovar os certificados, o programa de renovação precisa **provar** para a autoridade (Let's Encrypt) que ele realmente **"possui" e controla esse domínio**.
|
||||
|
||||
Para fazer isso, e acomodar as necessidades de diferentes aplicações, existem diferentes opções para esse programa. Algumas escolhas populares são:
|
||||
|
||||
* Modificar alguns registros DNS
|
||||
* **Modificar alguns registros DNS**.
|
||||
* Para isso, o programa de renovação precisa ter suporte às APIs do provedor DNS, então, dependendo do provedor DNS que você utilize, isso pode ou não ser uma opção viável.
|
||||
* Executar como um servidor (ao menos durante o processo de aquisição do certificado) no endereço IP público associado com o domínio.
|
||||
* **Executar como um servidor** (ao menos durante o processo de aquisição do certificado) no endereço IP público associado com o domínio.
|
||||
* Como dito anteriormente, apenas um processo pode estar ligado a uma porta e IP específicos.
|
||||
* Essa é uma dos motivos que fazem utilizar o mesmo Proxy de Terminação TLS para gerenciar a renovação de certificados ser tão útil.
|
||||
* Caso contrário, você pode ter que parar a execução do Proxy de Terminação TLS momentaneamente, inicializar o programa de renovação para adquirir os certificados, depois configurá-los com o Proxy de Terminação TLS, e então reiniciar o Proxy de Terminação TLS. Isso não é o ideal, já que sua(s) aplicação(ões) não vão estar disponíveis enquanto o Proxy de Terminação TLS estiver desligado.
|
||||
|
||||
Todo esse processo de renovação, enquanto o aplicativo ainda funciona, é uma das principais razões para preferir um sistema separado para gerenciar HTTPS com um Proxy de Terminação TLS em vez de usar os certificados TLS no servidor da aplicação diretamente (e.g. com o Uvicorn).
|
||||
Todo esse processo de renovação, enquanto o aplicativo ainda funciona, é uma das principais razões para preferir um **sistema separado para gerenciar HTTPS** com um Proxy de Terminação TLS em vez de usar os certificados TLS no servidor da aplicação diretamente (e.g. com o Uvicorn).
|
||||
|
||||
## Cabeçalhos encaminhados por Proxy { #proxy-forwarded-headers }
|
||||
|
||||
Ao usar um proxy para lidar com HTTPS, seu servidor de aplicação (por exemplo, Uvicorn via FastAPI CLI) não sabe nada sobre o processo de HTTPS; ele se comunica com HTTP simples com o Proxy de Terminação TLS.
|
||||
Ao usar um proxy para lidar com HTTPS, seu **servidor de aplicação** (por exemplo, Uvicorn via FastAPI CLI) não sabe nada sobre o processo de HTTPS; ele se comunica com HTTP simples com o **Proxy de Terminação TLS**.
|
||||
|
||||
Esse proxy normalmente define alguns cabeçalhos HTTP dinamicamente antes de transmitir a requisição para o servidor de aplicação, para informar ao servidor de aplicação que a requisição está sendo encaminhada pelo proxy.
|
||||
Esse **proxy** normalmente define alguns cabeçalhos HTTP dinamicamente antes de transmitir a requisição para o **servidor de aplicação**, para informar ao servidor de aplicação que a requisição está sendo **encaminhada** pelo proxy.
|
||||
|
||||
/// note | Detalhes Técnicos
|
||||
|
||||
@@ -206,11 +206,11 @@ Os cabeçalhos do proxy são:
|
||||
|
||||
///
|
||||
|
||||
No entanto, como o servidor de aplicação não sabe que está atrás de um proxy confiável, por padrão ele não confiaria nesses cabeçalhos.
|
||||
No entanto, como o **servidor de aplicação** não sabe que está atrás de um **proxy** confiável, por padrão ele não confiaria nesses cabeçalhos.
|
||||
|
||||
Mas você pode configurar o servidor de aplicação para confiar nos cabeçalhos encaminhados enviados pelo proxy. Se você estiver usando o FastAPI CLI, pode usar a opção de CLI `--forwarded-allow-ips` para dizer de quais IPs ele deve confiar nesses cabeçalhos encaminhados.
|
||||
Mas você pode configurar o **servidor de aplicação** para confiar nos cabeçalhos *encaminhados* enviados pelo **proxy**. Se você estiver usando o FastAPI CLI, pode usar a *Opção de CLI* `--forwarded-allow-ips` para dizer de quais IPs ele deve confiar nesses cabeçalhos *encaminhados*.
|
||||
|
||||
Por exemplo, se o servidor de aplicação só estiver recebendo comunicação do proxy confiável, você pode defini-lo como `--forwarded-allow-ips="*"` para fazê-lo confiar em todos os IPs de entrada, já que ele só receberá requisições de seja lá qual for o IP usado pelo proxy.
|
||||
Por exemplo, se o **servidor de aplicação** só estiver recebendo comunicação do **proxy** confiável, você pode defini-lo como `--forwarded-allow-ips="*"` para fazê-lo confiar em todos os IPs de entrada, já que ele só receberá requisições de seja lá qual for o IP usado pelo **proxy**.
|
||||
|
||||
Dessa forma, a aplicação seria capaz de saber qual é sua própria URL pública, se está usando HTTPS, o domínio, etc.
|
||||
|
||||
@@ -224,8 +224,8 @@ Você pode saber mais sobre isso na documentação em [Atrás de um Proxy - Habi
|
||||
|
||||
## Recapitulando { #recap }
|
||||
|
||||
Possuir HTTPS habilitado na sua aplicação é bastante importante, e até crítico na maioria dos casos. A maior parte do esforço que você tem que colocar sobre o HTTPS como desenvolvedor está em entender esses conceitos e como eles funcionam.
|
||||
Possuir **HTTPS** habilitado na sua aplicação é bastante importante, e até **crítico** na maioria dos casos. A maior parte do esforço que você tem que colocar sobre o HTTPS como desenvolvedor está em **entender esses conceitos** e como eles funcionam.
|
||||
|
||||
Mas uma vez que você saiba o básico de HTTPS para desenvolvedores, você pode combinar e configurar diferentes ferramentas facilmente para gerenciar tudo de uma forma simples.
|
||||
Mas uma vez que você saiba o básico de **HTTPS para desenvolvedores**, você pode combinar e configurar diferentes ferramentas facilmente para gerenciar tudo de uma forma simples.
|
||||
|
||||
Em alguns dos próximos capítulos, eu mostrarei para você vários exemplos concretos de como configurar o HTTPS para aplicações FastAPI. 🔒
|
||||
Em alguns dos próximos capítulos, eu mostrarei para você vários exemplos concretos de como configurar o **HTTPS** para aplicações **FastAPI**. 🔒
|
||||
|
||||
@@ -53,10 +53,9 @@ A principal coisa que você precisa para executar uma aplicação **FastAPI** (o
|
||||
Existem diversas alternativas, incluindo:
|
||||
|
||||
* [Uvicorn](https://www.uvicorn.dev/): um servidor ASGI de alta performance.
|
||||
* [Hypercorn](https://hypercorn.readthedocs.io/): um servidor ASGI compatível com HTTP/2, Trio e outros recursos.
|
||||
* [Hypercorn](https://hypercorn.readthedocs.io/): um servidor ASGI compatível com HTTP/2, Trio e outras funcionalidades.
|
||||
* [Daphne](https://github.com/django/daphne): servidor ASGI construído para Django Channels.
|
||||
* [Granian](https://github.com/emmett-framework/granian): um servidor HTTP Rust para aplicações Python.
|
||||
* [NGINX Unit](https://unit.nginx.org/howto/fastapi/): NGINX Unit é um runtime de aplicação web leve e versátil.
|
||||
|
||||
## Máquina Servidora e Programa Servidor { #server-machine-and-server-program }
|
||||
|
||||
@@ -137,7 +136,7 @@ Uvicorn e outros servidores suportam a opção `--reload` que é útil durante o
|
||||
|
||||
A opção `--reload` consome muito mais recursos, é mais instável, etc.
|
||||
|
||||
Ela ajuda muito durante o **desenvolvimento**, mas você **não deve** usá-la em **produção**.
|
||||
Ela ajuda muito durante o **desenvolvimento**, mas você **não deveria** usá-la em **produção**.
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ Como você viu no capítulo anterior sobre [Conceitos de implantação](concepts
|
||||
|
||||
Aqui mostrarei como usar o **Uvicorn** com **processos de trabalho** usando o comando `fastapi` ou o comando `uvicorn` diretamente.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Se você estiver usando contêineres, por exemplo com Docker ou Kubernetes, falarei mais sobre isso no próximo capítulo: [FastAPI em contêineres - Docker](docker.md).
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Suporte a Editores { #editor-support }
|
||||
|
||||
A [FastAPI Extension](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) oficial melhora seu fluxo de trabalho de desenvolvimento com descoberta e navegação de *operação de rota*, além de implantação no FastAPI Cloud e transmissão ao vivo de logs.
|
||||
A [FastAPI Extension](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) oficial melhora seu fluxo de trabalho de desenvolvimento FastAPI com descoberta e navegação de *operação de rota*, além de implantação no FastAPI Cloud e transmissão ao vivo de logs.
|
||||
|
||||
Para mais detalhes sobre a extensão, consulte o README no [repositório do GitHub](https://github.com/fastapi/fastapi-vscode).
|
||||
|
||||
|
||||
@@ -289,7 +289,7 @@ Essas informações serão úteis ao aprender sobre [Ambientes Virtuais](virtual
|
||||
|
||||
## Conclusão { #conclusion }
|
||||
|
||||
Com isso, você deve ter uma compreensão básica do que são **variáveis de ambiente** e como usá-las em Python.
|
||||
Com isso, você deveria ter uma compreensão básica do que são **variáveis de ambiente** e como usá-las em Python.
|
||||
|
||||
Você também pode ler mais sobre elas na [Wikipedia para Variáveis de Ambiente](https://en.wikipedia.org/wiki/Environment_variable).
|
||||
|
||||
|
||||
+20
-20
@@ -1,15 +1,15 @@
|
||||
# Recursos { #features }
|
||||
# Funcionalidades { #features }
|
||||
|
||||
## Recursos do FastAPI { #fastapi-features }
|
||||
## Funcionalidades do FastAPI { #fastapi-features }
|
||||
|
||||
**FastAPI** te oferece o seguinte:
|
||||
|
||||
### Baseado em padrões abertos { #based-on-open-standards }
|
||||
|
||||
* [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification) para criação de APIs, incluindo declarações de <dfn title="também conhecido como: endpoints, rotas">caminho</dfn> <dfn title="também conhecido como métodos HTTP, como POST, GET, PUT, DELETE">operações</dfn>, parâmetros, requisições de corpo, segurança etc.
|
||||
* [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification) para criação de APIs, incluindo declarações de <dfn title="também conhecido como: endpoints, rotas">path</dfn> <dfn title="também conhecido como métodos HTTP, como POST, GET, PUT, DELETE">operações</dfn>, parâmetros, corpos de requisição, segurança etc.
|
||||
* Documentação automática de modelos de dados com [**JSON Schema**](https://json-schema.org/) (já que o OpenAPI em si é baseado no JSON Schema).
|
||||
* Projetado em torno desses padrões, após um estudo meticuloso. Em vez de uma camada improvisada por cima.
|
||||
* Isso também permite o uso de **geração de código do cliente** automaticamente em muitas linguagens.
|
||||
* Isso também permite o uso de **geração de código de cliente** automaticamente em muitas linguagens.
|
||||
|
||||
### Documentação automática { #automatic-docs }
|
||||
|
||||
@@ -75,7 +75,7 @@ Passe as chaves e valores do dicionário `second_user_data` diretamente como arg
|
||||
|
||||
Todo o framework foi projetado para ser fácil e intuitivo de usar, todas as decisões foram testadas em vários editores antes do início do desenvolvimento, para garantir a melhor experiência de desenvolvimento.
|
||||
|
||||
Na pesquisa de desenvolvedores Python, ficou claro [que um dos recursos mais utilizados é o "preenchimento automático"](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features).
|
||||
Nas pesquisas de desenvolvedores Python, ficou claro [que uma das funcionalidades mais utilizadas é o "preenchimento automático"](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features).
|
||||
|
||||
Todo o framework **FastAPI** é feito para satisfazer isso. O preenchimento automático funciona em todos os lugares.
|
||||
|
||||
@@ -97,9 +97,9 @@ Sem a necessidade de digitar nomes de chaves erroneamente, ir e voltar entre doc
|
||||
|
||||
### Breve { #short }
|
||||
|
||||
Há **padrões** sensíveis para tudo, com configurações adicionais em todos os lugares. Todos os parâmetros podem ser regulados para fazer o que você precisa e para definir a API que você necessita.
|
||||
Há **valores padrão** sensíveis para tudo, com configurações adicionais em todos os lugares. Todos os parâmetros podem ser regulados para fazer o que você precisa e para definir a API que você necessita.
|
||||
|
||||
Por padrão, tudo **"simplesmente funciona"**.
|
||||
Mas, por padrão, tudo **"simplesmente funciona"**.
|
||||
|
||||
### Validação { #validation }
|
||||
|
||||
@@ -121,7 +121,7 @@ Toda a validação é controlada pelo robusto e bem estabelecido **Pydantic**.
|
||||
|
||||
Segurança e autenticação integradas. Sem nenhum compromisso com bancos de dados ou modelos de dados.
|
||||
|
||||
Todos os esquemas de seguranças definidos no OpenAPI, incluindo:
|
||||
Todos os esquemas de segurança definidos no OpenAPI, incluindo:
|
||||
|
||||
* HTTP Basic.
|
||||
* **OAuth2** (também com **tokens JWT**). Confira o tutorial em [OAuth2 com JWT](tutorial/security/oauth2-jwt.md).
|
||||
@@ -130,9 +130,9 @@ Todos os esquemas de seguranças definidos no OpenAPI, incluindo:
|
||||
* parâmetros da Query.
|
||||
* Cookies etc.
|
||||
|
||||
Além disso, todos os recursos de segurança do Starlette (incluindo **cookies de sessão**).
|
||||
Além disso, todas as funcionalidades de segurança do Starlette (incluindo **cookies de sessão**).
|
||||
|
||||
Tudo construído como ferramentas e componentes reutilizáveis que são fáceis de integrar com seus sistemas, armazenamento de dados, banco de dados relacionais e não-relacionais etc.
|
||||
Tudo construído como ferramentas e componentes reutilizáveis que são fáceis de integrar com seus sistemas, armazenamentos de dados, bancos de dados relacionais e NoSQL etc.
|
||||
|
||||
### Injeção de dependência { #dependency-injection }
|
||||
|
||||
@@ -142,40 +142,40 @@ FastAPI inclui um sistema de <dfn title='também conhecido como "componentes", "
|
||||
* Tudo **automaticamente controlado** pelo framework.
|
||||
* Todas as dependências podem pedir dados das requisições e **ampliar** as restrições e documentação automática da **operação de rota**.
|
||||
* **Validação automática** mesmo para parâmetros da *operação de rota* definidos em dependências.
|
||||
* Suporte para sistemas de autenticação complexos, **conexões com banco de dados** etc.
|
||||
* Suporte para sistemas complexos de autenticação de usuários, **conexões com banco de dados** etc.
|
||||
* **Sem comprometer** os bancos de dados, frontends etc. Mas fácil integração com todos eles.
|
||||
|
||||
### "Plug-ins" ilimitados { #unlimited-plug-ins }
|
||||
|
||||
Ou, de outra forma, sem a necessidade deles, importe e use o código que precisar.
|
||||
|
||||
Qualquer integração é projetada para ser tão simples de usar (com dependências) que você pode criar um "plug-in" para suas aplicações com 2 linhas de código usando a mesma estrutura e sintaxe para as suas *operações de rota*.
|
||||
Qualquer integração é projetada para ser tão simples de usar (com dependências) que você pode criar um "plug-in" para sua aplicação com 2 linhas de código usando a mesma estrutura e sintaxe usadas para as suas *operações de rota*.
|
||||
|
||||
### Testado { #tested }
|
||||
|
||||
* 100% <dfn title="A quantidade de código que é testada automaticamente">de cobertura de testes</dfn>.
|
||||
* 100% do código com <dfn title="Anotações de tipo do Python, com isso seu editor e ferramentas externas podem te dar um suporte melhor">anotações de tipo</dfn>.
|
||||
* Base de código 100% <dfn title="Anotações de tipo do Python, com isso seu editor e ferramentas externas podem te dar um suporte melhor">anotada com tipos</dfn>.
|
||||
* Usado para aplicações em produção.
|
||||
|
||||
## Recursos do Starlette { #starlette-features }
|
||||
## Funcionalidades do Starlette { #starlette-features }
|
||||
|
||||
**FastAPI** é totalmente compatível com (e baseado no) [**Starlette**](https://www.starlette.dev/). Então, qualquer código adicional Starlette que você tiver, também funcionará.
|
||||
|
||||
`FastAPI` é na verdade uma sub-classe do `Starlette`. Então, se você já conhece ou usa Starlette, a maioria das funcionalidades se comportará da mesma forma.
|
||||
|
||||
Com **FastAPI**, você terá todos os recursos do **Starlette** (já que FastAPI é apenas um Starlette com esteróides):
|
||||
Com **FastAPI**, você terá todas as funcionalidades do **Starlette** (já que FastAPI é apenas um Starlette com esteroides):
|
||||
|
||||
* Desempenho realmente impressionante. É [um dos frameworks Python disponíveis mais rápidos, a par com o **NodeJS** e **Go**](https://github.com/encode/starlette#performance).
|
||||
* Suporte a **WebSocket**.
|
||||
* Tarefas em processo background.
|
||||
* Eventos na inicialização e encerramento.
|
||||
* Eventos de inicialização e encerramento.
|
||||
* Cliente de testes construído sobre HTTPX.
|
||||
* Respostas em **CORS**, GZip, Static Files, Streaming.
|
||||
* Respostas **CORS**, GZip, Static Files, Streaming.
|
||||
* Suporte a **Session e Cookie**.
|
||||
* 100% de cobertura de testes.
|
||||
* 100% do código utilizando anotações de tipo.
|
||||
* Base de código 100% com anotações de tipo.
|
||||
|
||||
## Recursos do Pydantic { #pydantic-features }
|
||||
## Funcionalidades do Pydantic { #pydantic-features }
|
||||
|
||||
**FastAPI** é totalmente compatível com (e baseado no) [**Pydantic**](https://docs.pydantic.dev/). Então, qualquer código Pydantic adicional que você tiver, também funcionará.
|
||||
|
||||
@@ -185,7 +185,7 @@ Isso também significa que em muitos casos você poderá passar o mesmo objeto q
|
||||
|
||||
O mesmo se aplica no sentido inverso, em muitos casos você poderá simplesmente passar o objeto que você recebeu do banco de dados **diretamente para o cliente**.
|
||||
|
||||
Com **FastAPI** você terá todos os recursos do **Pydantic** (já que FastAPI utiliza o Pydantic para todo o controle dos dados):
|
||||
Com **FastAPI** você terá todas as funcionalidades do **Pydantic** (já que FastAPI utiliza o Pydantic para todo o controle dos dados):
|
||||
|
||||
* **Sem pegadinhas**:
|
||||
* Sem novas definições de esquema de micro-linguagem para aprender.
|
||||
|
||||
@@ -30,7 +30,7 @@ Ao adicionar uma estrela, outras pessoas conseguirão encontrá-lo com mais faci
|
||||
|
||||
## Acompanhe o repositório no GitHub para lançamentos { #watch-the-github-repository-for-releases }
|
||||
|
||||
Você pode “acompanhar” (watch) o FastAPI no GitHub (clicando no botão “watch” no canto superior direito): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀
|
||||
Você pode “acompanhar” o FastAPI no GitHub (clicando no botão “watch” no canto superior direito): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀
|
||||
|
||||
Lá você pode selecionar “Apenas lançamentos”.
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Configure a UI do Swagger { #configure-swagger-ui }
|
||||
|
||||
|
||||
Você pode configurar alguns [parâmetros extras da UI do Swagger](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).
|
||||
|
||||
Para configurá-los, passe o argumento `swagger_ui_parameters` ao criar o objeto da aplicação `FastAPI()` ou para a função `get_swagger_ui_html()`.
|
||||
|
||||
@@ -10,7 +10,7 @@ Por exemplo, se você quiser ler ou manipular o corpo da requisição antes que
|
||||
|
||||
Isso é um recurso "avançado".
|
||||
|
||||
Se você for um iniciante em **FastAPI** você deve considerar pular essa seção.
|
||||
Se você está apenas começando com **FastAPI**, talvez queira pular esta seção.
|
||||
|
||||
///
|
||||
|
||||
@@ -40,7 +40,7 @@ Primeiro, criamos uma classe `GzipRequest`, que irá sobrescrever o método `Req
|
||||
|
||||
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.
|
||||
Dessa forma, a mesma classe de rota pode lidar com requisições comprimidas com gzip ou não comprimidas.
|
||||
|
||||
{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}
|
||||
|
||||
@@ -84,7 +84,7 @@ Mas por causa das nossas mudanças em `GzipRequest.body`, o corpo da requisiçã
|
||||
|
||||
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)).
|
||||
|
||||
Mas esse exemplo ainda é valido e mostra como interagir com os componentes internos.
|
||||
Mas esse exemplo ainda é válido e mostra como interagir com os componentes internos.
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -25,9 +25,17 @@ E essa função `get_openapi()` recebe como parâmetros:
|
||||
* `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`.
|
||||
* `routes`: As rotas da aplicação, obtidas de `app.routes`. O FastAPI as usa para coletar as *operações de rota* registradas, incluindo as dos routers incluídos.
|
||||
|
||||
/// info | Informação
|
||||
/// tip | Detalhes Técnicos
|
||||
|
||||
`app.routes` é uma árvore de rotas de baixo nível. Ela pode incluir rotas candidatas que o FastAPI usa internamente para routers incluídos, não apenas objetos finais `APIRoute`.
|
||||
|
||||
Você ainda pode passar `app.routes` para `get_openapi()`. O FastAPI vai percorrer essa árvore de rotas para coletar as operações de rota efetivas.
|
||||
|
||||
///
|
||||
|
||||
/// note | Nota
|
||||
|
||||
O parâmetro `summary` está disponível no OpenAPI 3.1.0 e superior, suportado pelo FastAPI 0.99.0 e superior.
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# GraphQL { #graphql }
|
||||
|
||||
|
||||
Como o **FastAPI** é baseado no padrão **ASGI**, é muito fácil integrar qualquer biblioteca **GraphQL** também compatível com ASGI.
|
||||
|
||||
Você pode combinar *operações de rota* normais do FastAPI com GraphQL na mesma aplicação.
|
||||
|
||||
@@ -8,6 +8,8 @@ O FastAPI versão 0.119.0 introduziu suporte parcial ao Pydantic v1 a partir de
|
||||
|
||||
O FastAPI 0.126.0 removeu o suporte ao Pydantic v1, enquanto ainda oferece suporte a `pydantic.v1` por mais algum tempo.
|
||||
|
||||
O FastAPI 0.128.0 também removeu o suporte a `pydantic.v1`, então as versões mais recentes do FastAPI exigem o Pydantic v2.
|
||||
|
||||
/// warning | Atenção
|
||||
|
||||
A equipe do Pydantic interrompeu o suporte ao Pydantic v1 para as versões mais recentes do Python, a partir do **Python 3.14**.
|
||||
@@ -54,6 +56,16 @@ Isso significa que você pode instalar a versão mais recente do Pydantic v2 e i
|
||||
|
||||
### Suporte do FastAPI ao Pydantic v1 no v2 { #fastapi-support-for-pydantic-v1-in-v2 }
|
||||
|
||||
/// warning | Atenção
|
||||
|
||||
Este suporte do FastAPI para modelos `pydantic.v1` foi adicionado no **FastAPI 0.119.0** e removido no **FastAPI 0.128.0**. Ele foi pensado como uma ajuda temporária para a migração para o Pydantic v2.
|
||||
|
||||
Nas versões atuais do FastAPI, usar um modelo `pydantic.v1` na sua aplicação gerará um erro.
|
||||
|
||||
O restante desta seção descreve o suporte temporário disponível apenas nessas versões antigas.
|
||||
|
||||
///
|
||||
|
||||
Desde o FastAPI 0.119.0, há também suporte parcial ao Pydantic v1 a partir de dentro do Pydantic v2, para facilitar a migração para o v2.
|
||||
|
||||
Assim, você pode atualizar o Pydantic para a versão 2 mais recente e alterar os imports para usar o submódulo `pydantic.v1`, e em muitos casos tudo simplesmente funcionará.
|
||||
@@ -122,6 +134,12 @@ Se você precisar usar algumas das ferramentas específicas do FastAPI para par
|
||||
|
||||
### Migre em etapas { #migrate-in-steps }
|
||||
|
||||
/// warning | Atenção
|
||||
|
||||
A migração gradual usando modelos Pydantic v1 e v2 na mesma aplicação descrita abaixo só funciona do **FastAPI 0.119.0 ao 0.127.x**. Ela foi removida no **FastAPI 0.128.0**, e as versões mais recentes exigem modelos **Pydantic v2**.
|
||||
|
||||
///
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Primeiro tente com o `bump-pydantic`, se seus testes passarem e isso funcionar, então você concluiu tudo com um único comando. ✨
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Esquemas OpenAPI Separados para Entrada e Saída ou Não { #separate-openapi-schemas-for-input-and-output-or-not }
|
||||
|
||||
|
||||
Desde que o **Pydantic v2** foi lançado, o OpenAPI gerado é um pouco mais exato e **correto** do que antes. 😎
|
||||
|
||||
De fato, em alguns casos, ele terá até **dois JSON Schemas** no OpenAPI para o mesmo modelo Pydantic, para entrada e saída, dependendo se eles possuem **valores padrão**.
|
||||
@@ -38,7 +39,7 @@ Mas se você usar o mesmo modelo como saída, como aqui:
|
||||
|
||||
### Modelo para Dados de Resposta de Saída { #model-for-output-response-data }
|
||||
|
||||
Se você interagir com a documentação e verificar a resposta, mesmo que o código não tenha adicionado nada em um dos campos `description`, a resposta JSON contém o valor padrão (`null`):
|
||||
Se você interagir com a documentação e verificar a resposta, mesmo que o código não tenha adicionado nada em um dos campos `description`, a response JSON contém o valor padrão (`null`):
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image02.png">
|
||||
@@ -81,11 +82,11 @@ Com esse recurso do **Pydantic v2**, sua documentação da API fica mais **preci
|
||||
|
||||
Agora, há alguns casos em que você pode querer ter o **mesmo esquema para entrada e saída**.
|
||||
|
||||
Provavelmente, o principal caso de uso para isso é se você já tem algum código de cliente/SDK gerado automaticamente e não quer atualizar todo o código de cliente/SDK gerado ainda, você provavelmente vai querer fazer isso em algum momento, mas talvez não agora.
|
||||
Provavelmente, o principal caso de uso para isso é se você já tem algum código de cliente/SDKs gerado automaticamente e não quer atualizar todo o código de cliente/SDKs gerado ainda, você provavelmente vai querer fazer isso em algum momento, mas talvez não agora.
|
||||
|
||||
Nesse caso, você pode desativar esse recurso no **FastAPI**, com o parâmetro `separate_input_output_schemas=False`.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
O suporte para `separate_input_output_schemas` foi adicionado no FastAPI `0.102.0`. 🤓
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ include_yaml:
|
||||
|
||||
---
|
||||
|
||||
FastAPI é um framework web moderno e rápido (alta performance) para construção de APIs com Python, baseado nos type hints padrões do Python.
|
||||
FastAPI é um framework web moderno e rápido (alta performance) para construção de APIs com Python, baseado nas anotações de tipo padrão do Python.
|
||||
|
||||
Os recursos chave são:
|
||||
|
||||
@@ -46,7 +46,7 @@ Os recursos chave são:
|
||||
* **Rápido para codar**: Aumenta a velocidade para desenvolver recursos entre 200% a 300%. *
|
||||
* **Poucos bugs**: Reduz cerca de 40% de erros induzidos por humanos (desenvolvedores). *
|
||||
* **Intuitivo**: Grande suporte a editores. <dfn title="também conhecido como: autocompletar, preenchimento automático, IntelliSense">Completação</dfn> em todos os lugares. Menos tempo debugando.
|
||||
* **Fácil**: Projetado para ser fácil de aprender e usar. Menos tempo lendo docs.
|
||||
* **Fácil**: Projetado para ser fácil de aprender e usar. Menos tempo lendo documentação.
|
||||
* **Enxuto**: Minimize duplicação de código. Múltiplas funcionalidades para cada declaração de parâmetro. Menos bugs.
|
||||
* **Robusto**: Tenha código pronto para produção. E com documentação interativa automática.
|
||||
* **Baseado em padrões**: Baseado em (e totalmente compatível com) os padrões abertos para APIs: [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (anteriormente conhecido como Swagger) e [JSON Schema](https://json-schema.org/).
|
||||
@@ -239,7 +239,7 @@ async def read_item(item_id: int, q: str | None = None):
|
||||
|
||||
**Nota**:
|
||||
|
||||
Se você não sabe, verifique a seção _"Com pressa?"_ sobre [`async` e `await` nas docs](https://fastapi.tiangolo.com/pt/async/#in-a-hurry).
|
||||
Se você não sabe, verifique a seção _"Com pressa?"_ sobre [`async` e `await` na documentação](https://fastapi.tiangolo.com/pt/async/#in-a-hurry).
|
||||
|
||||
</details>
|
||||
|
||||
@@ -469,7 +469,7 @@ Experimente mudar a seguinte linha:
|
||||
... "item_price": item.price ...
|
||||
```
|
||||
|
||||
...e veja como seu editor irá auto-completar os atributos e saberá os tipos:
|
||||
...e veja como seu editor irá autocompletar os atributos e saberá os tipos:
|
||||
|
||||

|
||||
|
||||
@@ -492,9 +492,7 @@ Para um exemplo mais completo incluindo mais recursos, veja o <a href="https://f
|
||||
|
||||
### Implemente sua aplicação (opcional) { #deploy-your-app-optional }
|
||||
|
||||
Você pode opcionalmente implantar sua aplicação FastAPI na [FastAPI Cloud](https://fastapicloud.com), vá e entre na lista de espera se ainda não o fez. 🚀
|
||||
|
||||
Se você já tem uma conta na **FastAPI Cloud** (nós convidamos você da lista de espera 😉), pode implantar sua aplicação com um único comando.
|
||||
Você pode opcionalmente implantar sua aplicação FastAPI na [FastAPI Cloud](https://fastapicloud.com) com um único comando. 🚀
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -510,6 +508,8 @@ Deploying to FastAPI Cloud...
|
||||
|
||||
</div>
|
||||
|
||||
A CLI detectará automaticamente sua aplicação FastAPI e a implantará na nuvem. Se você não estiver autenticado, o navegador será aberto para concluir o processo de autenticação.
|
||||
|
||||
É isso! Agora você pode acessar sua aplicação nesse URL. ✨
|
||||
|
||||
#### Sobre a FastAPI Cloud { #about-fastapi-cloud }
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
# Full Stack FastAPI Template { #full-stack-fastapi-template }
|
||||
|
||||
_Templates_, embora tipicamente venham com alguma configuração específica, são desenhados para serem flexíveis e customizáveis. Isso permite que você os modifique e adapte para as especificações do seu projeto, fazendo-os um excelente ponto de partida. 🏁
|
||||
Templates, embora tipicamente venham com alguma configuração específica, são desenhados para serem flexíveis e customizáveis. Isso permite que você os modifique e adapte para as especificações do seu projeto, fazendo-os um excelente ponto de partida. 🏁
|
||||
|
||||
Você pode usar esse _template_ para começar, já que ele inclui várias configurações iniciais, segurança, banco de dados, e alguns _endpoints_ de API já feitos para você.
|
||||
Você pode usar esse template para começar, já que ele inclui várias configurações iniciais, segurança, banco de dados e alguns endpoints de API já feitos para você.
|
||||
|
||||
Repositório GitHub: [Full Stack FastAPI Template](https://github.com/tiangolo/full-stack-fastapi-template)
|
||||
|
||||
## Full Stack FastAPI Template - Pilha de Tecnologias e Recursos { #full-stack-fastapi-template-technology-stack-and-features }
|
||||
|
||||
- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/pt) para a API do backend em Python.
|
||||
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) para as interações do Python com bancos de dados SQL (ORM).
|
||||
- 🔍 [Pydantic](https://docs.pydantic.dev), usado pelo FastAPI, para validação de dados e gerenciamento de configurações.
|
||||
- 💾 [PostgreSQL](https://www.postgresql.org) como banco de dados SQL.
|
||||
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) para as interações do Python com bancos de dados SQL (ORM).
|
||||
- 🔍 [Pydantic](https://docs.pydantic.dev), usado pelo FastAPI, para validação de dados e gerenciamento de configurações.
|
||||
- 💾 [PostgreSQL](https://www.postgresql.org) como banco de dados SQL.
|
||||
- 🚀 [React](https://react.dev) para o frontend.
|
||||
- 💃 Usando TypeScript, hooks, Vite, e outras partes de uma _stack_ frontend moderna.
|
||||
- 🎨 [Tailwind CSS](https://tailwindcss.com) e [shadcn/ui](https://ui.shadcn.com) para os componentes de frontend.
|
||||
- 🤖 Um cliente frontend automaticamente gerado.
|
||||
- 🧪 [Playwright](https://playwright.dev) para testes Ponta-a-Ponta.
|
||||
- 🦇 Suporte para modo escuro.
|
||||
- 💃 Usando TypeScript, hooks, Vite, e outras partes de uma stack frontend moderna.
|
||||
- 🎨 [Tailwind CSS](https://tailwindcss.com) e [shadcn/ui](https://ui.shadcn.com) para os componentes de frontend.
|
||||
- 🤖 Um cliente frontend automaticamente gerado.
|
||||
- 🧪 [Playwright](https://playwright.dev) para testes Ponta-a-Ponta.
|
||||
- 🦇 Suporte para modo escuro.
|
||||
- 🐋 [Docker Compose](https://www.docker.com) para desenvolvimento e produção.
|
||||
- 🔒 Hash seguro de senhas por padrão.
|
||||
- 🔑 Autenticação JWT (JSON Web Token).
|
||||
@@ -25,4 +25,4 @@ Repositório GitHub: [Full Stack FastAPI Template](https://github.com/tiangolo/f
|
||||
- ✅ Testes com [Pytest](https://pytest.org).
|
||||
- 📞 [Traefik](https://traefik.io) como proxy reverso / balanceador de carga.
|
||||
- 🚢 Instruções de deployment usando Docker Compose, incluindo como configurar um proxy frontend com Traefik para gerenciar automaticamente certificados HTTPS.
|
||||
- 🏭 CI (Integração Contínua) e CD (_Deploy_ Contínuo) baseado em GitHub Actions.
|
||||
- 🏭 CI (integração contínua) e CD (deployment contínuo) baseados em GitHub Actions.
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
# Introdução aos tipos Python { #python-types-intro }
|
||||
|
||||
O Python possui suporte para "type hints" opcionais (também chamados de "type annotations").
|
||||
O Python possui suporte para "anotações de tipo" opcionais (também chamadas de "type annotations").
|
||||
|
||||
Esses **"type hints"** ou anotações são uma sintaxe especial que permite declarar o <dfn title="por exemplo: str, int, float, bool">tipo</dfn> de uma variável.
|
||||
Essas **"anotações de tipo"** ou anotações são uma sintaxe especial que permite declarar o <dfn title="por exemplo: str, int, float, bool">tipo</dfn> de uma variável.
|
||||
|
||||
Ao declarar tipos para suas variáveis, editores e ferramentas podem oferecer um melhor suporte.
|
||||
|
||||
Este é apenas um **tutorial rápido / atualização** sobre type hints do Python. Ele cobre apenas o mínimo necessário para usá-los com o **FastAPI**... que é realmente muito pouco.
|
||||
Este é apenas um **tutorial rápido / atualização** sobre anotações de tipo do Python. Ele cobre apenas o mínimo necessário para usá-las com o **FastAPI**... que é realmente muito pouco.
|
||||
|
||||
O **FastAPI** é todo baseado nesses type hints, eles oferecem muitas vantagens e benefícios.
|
||||
O **FastAPI** é todo baseado nessas anotações de tipo, elas oferecem muitas vantagens e benefícios.
|
||||
|
||||
Mas mesmo que você nunca use o **FastAPI**, você se beneficiaria de aprender um pouco sobre eles.
|
||||
Mas mesmo que você nunca use o **FastAPI**, você se beneficiaria de aprender um pouco sobre elas.
|
||||
|
||||
/// note | Nota
|
||||
|
||||
Se você é um especialista em Python e já sabe tudo sobre type hints, pule para o próximo capítulo.
|
||||
Se você é um especialista em Python e já sabe tudo sobre anotações de tipo, pule para o próximo capítulo.
|
||||
|
||||
///
|
||||
|
||||
@@ -34,7 +34,7 @@ A função faz o seguinte:
|
||||
|
||||
* Pega um `first_name` e `last_name`.
|
||||
* Converte a primeira letra de cada uma em maiúsculas com `title()`.
|
||||
* <dfn title="Coloca-os juntos, como um só. Com o conteúdo de um após o outro.">Concatena</dfn> com um espaço no meio.
|
||||
* <dfn title="Coloca-os juntos, como um só. Com o conteúdo de um após o outro.">Concatena</dfn>-os com um espaço no meio.
|
||||
|
||||
{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}
|
||||
|
||||
@@ -44,15 +44,15 @@ A função faz o seguinte:
|
||||
|
||||
Mas agora imagine que você estava escrevendo do zero.
|
||||
|
||||
Em algum momento você teria iniciado a definição da função, já tinha os parâmetros prontos...
|
||||
Em algum momento você começa a definir a função, e já tem os parâmetros prontos...
|
||||
|
||||
Mas então você deve chamar "esse método que converte a primeira letra em maiúscula".
|
||||
Mas então você tem que chamar "esse método que converte a primeira letra em maiúscula".
|
||||
|
||||
Era `upper`? Era `uppercase`? `first_uppercase`? `capitalize`?
|
||||
|
||||
Em seguida, tente com o velho amigo do programador, o preenchimento automático do editor.
|
||||
Então, você tenta com o velho amigo do programador, o preenchimento automático do editor.
|
||||
|
||||
Você digita o primeiro parâmetro da função, `first_name`, depois um ponto (`.`) e, em seguida, pressiona `Ctrl+Space` para acionar o preenchimento automático.
|
||||
Você digita o primeiro parâmetro da função, `first_name`, depois um ponto (`.`) e, em seguida, pressiona `Ctrl+Space` para acionar o preenchimento.
|
||||
|
||||
Mas, infelizmente, você não obtém nada útil:
|
||||
|
||||
@@ -76,7 +76,7 @@ para:
|
||||
|
||||
É isso aí.
|
||||
|
||||
Esses são os "type hints":
|
||||
Essas são as "anotações de tipo":
|
||||
|
||||
{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}
|
||||
|
||||
@@ -90,11 +90,11 @@ Isso não é o mesmo que declarar valores padrão como seria com:
|
||||
|
||||
Estamos usando dois pontos (`:`), não sinal de igual (`=`).
|
||||
|
||||
E adicionar type hints normalmente não muda o que acontece do que aconteceria sem eles.
|
||||
E adicionar anotações de tipo normalmente não muda o que acontece do que aconteceria sem elas.
|
||||
|
||||
Mas agora, imagine que você está novamente no meio da criação dessa função, mas com type hints.
|
||||
Mas agora, imagine que você está novamente no meio da criação dessa função, mas com anotações de tipo.
|
||||
|
||||
No mesmo ponto, você tenta acionar o preenchimento automático com o `Ctrl+Space` e vê:
|
||||
No mesmo ponto, você tenta acionar o autocompletar com `Ctrl+Space` e vê:
|
||||
|
||||
<img src="/img/python-types/image02.png">
|
||||
|
||||
@@ -104,11 +104,11 @@ Com isso, você pode rolar, vendo as opções, até encontrar o que "soa familia
|
||||
|
||||
## Mais motivação { #more-motivation }
|
||||
|
||||
Verifique esta função, ela já possui type hints:
|
||||
Verifique esta função, ela já possui anotações de tipo:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}
|
||||
|
||||
Como o editor conhece os tipos das variáveis, você não obtém apenas o preenchimento automático, mas também as verificações de erro:
|
||||
Como o editor conhece os tipos das variáveis, você não obtém apenas o preenchimento, mas também as verificações de erro:
|
||||
|
||||
<img src="/img/python-types/image04.png">
|
||||
|
||||
@@ -118,9 +118,9 @@ Agora você sabe que precisa corrigi-la, convertendo `age` em uma string com `st
|
||||
|
||||
## Declarando tipos { #declaring-types }
|
||||
|
||||
Você acabou de ver o local principal para declarar type hints. Como parâmetros de função.
|
||||
Você acabou de ver o local principal para declarar anotações de tipo. Como parâmetros de função.
|
||||
|
||||
Este também é o principal local em que você os usaria com o **FastAPI**.
|
||||
Este também é o principal local em que você as usaria com o **FastAPI**.
|
||||
|
||||
### Tipos simples { #simple-types }
|
||||
|
||||
@@ -137,7 +137,7 @@ Você pode usar, por exemplo:
|
||||
|
||||
### Módulo `typing` { #typing-module }
|
||||
|
||||
Para alguns casos adicionais, você pode precisar importar alguns itens do módulo padrão `typing`, por exemplo, quando quiser declarar que algo pode ter "qualquer tipo", você pode usar `Any` de `typing`:
|
||||
Para alguns casos de uso adicionais, você pode precisar importar alguns itens do módulo padrão `typing`, por exemplo, quando quiser declarar que algo pode ter "qualquer tipo", você pode usar `Any` de `typing`:
|
||||
|
||||
```python
|
||||
from typing import Any
|
||||
@@ -149,11 +149,11 @@ def some_function(data: Any):
|
||||
|
||||
### Tipos genéricos { #generic-types }
|
||||
|
||||
Alguns tipos podem receber "parâmetros de tipo" entre colchetes, para definir seus tipos internos, por exemplo, uma "lista de strings" seria declarada como `list[str]`.
|
||||
Alguns tipos podem receber "parâmetros de tipo" entre colchetes, para definir seus tipos internos, por exemplo, uma "list de strings" seria declarada como `list[str]`.
|
||||
|
||||
Esses tipos que podem receber parâmetros de tipo são chamados **tipos genéricos** ou **genéricos**.
|
||||
|
||||
Você pode usar os mesmos tipos internos como genéricos (com colchetes e tipos dentro):
|
||||
Você pode usar os mesmos tipos embutidos como genéricos (com colchetes e tipos dentro):
|
||||
|
||||
* `list`
|
||||
* `tuple`
|
||||
@@ -168,7 +168,7 @@ Declare a variável, com a mesma sintaxe com dois pontos (`:`).
|
||||
|
||||
Como o tipo, coloque `list`.
|
||||
|
||||
Como a lista é um tipo que contém tipos internos, você os coloca entre colchetes:
|
||||
Como a list é um tipo que contém alguns tipos internos, você os coloca entre colchetes:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}
|
||||
|
||||
@@ -180,15 +180,15 @@ Neste caso, `str` é o parâmetro de tipo passado para `list`.
|
||||
|
||||
///
|
||||
|
||||
Isso significa: "a variável `items` é uma `list`, e cada um dos itens desta lista é uma `str`".
|
||||
Isso significa: "a variável `items` é uma `list`, e cada um dos itens desta list é uma `str`".
|
||||
|
||||
Ao fazer isso, seu editor pode fornecer suporte mesmo durante o processamento de itens da lista:
|
||||
Ao fazer isso, seu editor pode fornecer suporte mesmo durante o processamento de itens da list:
|
||||
|
||||
<img src="/img/python-types/image05.png">
|
||||
|
||||
Sem tipos, isso é quase impossível de alcançar.
|
||||
|
||||
Observe que a variável `item` é um dos elementos da lista `items`.
|
||||
Observe que a variável `item` é um dos elementos da list `items`.
|
||||
|
||||
E, ainda assim, o editor sabe que é um `str` e fornece suporte para isso.
|
||||
|
||||
@@ -213,7 +213,7 @@ O segundo parâmetro de tipo é para os valores do `dict`:
|
||||
|
||||
{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}
|
||||
|
||||
Isso significa que:
|
||||
Isso significa:
|
||||
|
||||
* A variável `prices` é um `dict`:
|
||||
* As chaves deste `dict` são do tipo `str` (digamos, o nome de cada item).
|
||||
@@ -275,7 +275,7 @@ Você declara a "forma" dos dados como classes com atributos.
|
||||
|
||||
E cada atributo tem um tipo.
|
||||
|
||||
Em seguida, você cria uma instância dessa classe com alguns valores e ela os validará, os converterá para o tipo apropriado (se for esse o caso) e fornecerá um objeto com todos os dados.
|
||||
Em seguida, você cria uma instância dessa classe com alguns valores e ela validará os valores, os converterá para o tipo apropriado (se for esse o caso) e fornecerá um objeto com todos os dados.
|
||||
|
||||
E você recebe todo o suporte do editor com esse objeto resultante.
|
||||
|
||||
@@ -285,7 +285,7 @@ Um exemplo da documentação oficial do Pydantic:
|
||||
|
||||
/// note | Nota
|
||||
|
||||
Para saber mais sobre o [Pydantic, verifique a documentação](https://docs.pydantic.dev/).
|
||||
Para saber mais sobre [Pydantic, verifique a documentação](https://docs.pydantic.dev/).
|
||||
|
||||
///
|
||||
|
||||
@@ -293,9 +293,9 @@ O **FastAPI** é todo baseado em Pydantic.
|
||||
|
||||
Você verá muito mais disso na prática no [Tutorial - Guia do usuário](tutorial/index.md).
|
||||
|
||||
## Type Hints com Metadados de Anotações { #type-hints-with-metadata-annotations }
|
||||
## Anotações de Tipo com Anotações de Metadados { #type-hints-with-metadata-annotations }
|
||||
|
||||
O Python também possui uma funcionalidade que permite incluir **<dfn title="Informações sobre os dados, neste caso, informações sobre o tipo, por exemplo, uma descrição.">metadados</dfn> adicionais** nesses type hints utilizando `Annotated`.
|
||||
O Python também possui uma funcionalidade que permite incluir **<dfn title="Dados sobre os dados, neste caso, informações sobre o tipo, por exemplo, uma descrição.">metadados</dfn> adicionais** nessas anotações de tipo utilizando `Annotated`.
|
||||
|
||||
Você pode importar `Annotated` de `typing`.
|
||||
|
||||
@@ -305,7 +305,7 @@ O Python em si não faz nada com este `Annotated`. E para editores e outras ferr
|
||||
|
||||
Mas você pode utilizar este espaço dentro do `Annotated` para fornecer ao **FastAPI** metadados adicionais sobre como você deseja que a sua aplicação se comporte.
|
||||
|
||||
O importante aqui de se lembrar é que **o primeiro *type parameter*** que você informar ao `Annotated` é o **tipo de fato**. O resto é apenas metadado para outras ferramentas.
|
||||
O importante aqui de se lembrar é que **o primeiro *parâmetro de tipo*** que você informar ao `Annotated` é o **tipo de fato**. O resto é apenas metadados para outras ferramentas.
|
||||
|
||||
Por hora, você precisa apenas saber que o `Annotated` existe, e que ele é Python padrão. 😎
|
||||
|
||||
@@ -319,11 +319,11 @@ E também que o seu código será muito compatível com diversas outras ferramen
|
||||
|
||||
///
|
||||
|
||||
## Type hints no **FastAPI** { #type-hints-in-fastapi }
|
||||
## Anotações de tipo no **FastAPI** { #type-hints-in-fastapi }
|
||||
|
||||
O **FastAPI** aproveita esses type hints para fazer várias coisas.
|
||||
O **FastAPI** aproveita essas anotações de tipo para fazer várias coisas.
|
||||
|
||||
Com o **FastAPI**, você declara parâmetros com type hints e obtém:
|
||||
Com o **FastAPI**, você declara parâmetros com anotações de tipo e obtém:
|
||||
|
||||
* **Suporte ao editor**.
|
||||
* **Verificações de tipo**.
|
||||
|
||||
@@ -17,16 +17,16 @@ Digamos que você tenha uma estrutura de arquivos como esta:
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
│ ├── dependencies.py
|
||||
│ └── routers
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── items.py
|
||||
│ │ └── users.py
|
||||
│ └── internal
|
||||
│ ├── __init__.py
|
||||
│ └── admin.py
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
│ ├── dependencies.py
|
||||
│ └── routers
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── items.py
|
||||
│ │ └── users.py
|
||||
│ └── internal
|
||||
│ ├── __init__.py
|
||||
│ └── admin.py
|
||||
```
|
||||
|
||||
/// tip | Dica
|
||||
@@ -396,9 +396,9 @@ Ele incluirá todas as rotas daquele router como parte dele.
|
||||
|
||||
/// note | Detalhes Técnicos
|
||||
|
||||
Na verdade, ele criará internamente uma *operação de rota* para cada *operação de rota* que foi declarada no `APIRouter`.
|
||||
O FastAPI mantém o `APIRouter` original e seus `APIRoute`s ativos quando o router é incluído na aplicação principal.
|
||||
|
||||
Então, nos bastidores, ele realmente funcionará como se tudo fosse o mesmo aplicativo único.
|
||||
Isso significa que subclasses personalizadas de `APIRouter` e `APIRoute` ainda podem participar depois que o router é incluído.
|
||||
|
||||
///
|
||||
|
||||
@@ -406,7 +406,7 @@ Então, nos bastidores, ele realmente funcionará como se tudo fosse o mesmo apl
|
||||
|
||||
Você não precisa se preocupar com desempenho ao incluir routers.
|
||||
|
||||
Isso levará microssegundos e só acontecerá na inicialização.
|
||||
Isso foi projetado para ser leve e evitar adicionar overhead a cada request.
|
||||
|
||||
Então não afetará o desempenho. ⚡
|
||||
|
||||
@@ -461,7 +461,7 @@ Os `APIRouter`s não são "montados", eles não são isolados do resto do aplica
|
||||
|
||||
Isso ocorre porque queremos incluir suas *operações de rota* no esquema OpenAPI e nas interfaces de usuário.
|
||||
|
||||
Como não podemos simplesmente isolá-los e "montá-los" independentemente do resto, as *operações de rota* são "clonadas" (recriadas), não incluídas diretamente.
|
||||
O FastAPI mantém os routers e as operações de rota originais ativos e combina os prefixos, dependências, tags, responses e outros metadados do router ao tratar as requisições e gerar o OpenAPI.
|
||||
|
||||
///
|
||||
|
||||
@@ -532,4 +532,16 @@ Da mesma forma que você pode incluir um `APIRouter` em uma aplicação `FastAPI
|
||||
router.include_router(other_router)
|
||||
```
|
||||
|
||||
Certifique-se de fazer isso antes de incluir `router` na aplicação `FastAPI`, para que as *operações de rota* de `other_router` também sejam incluídas.
|
||||
Você pode fazer isso antes ou depois de incluir o `router` na aplicação `FastAPI`. O FastAPI ainda incluirá as *operações de rota* de `other_router` no roteamento e no OpenAPI.
|
||||
|
||||
O mesmo vale para *operações de rota* adicionadas depois aos routers. Elas também ficarão visíveis por meio da inclusão anterior.
|
||||
|
||||
/// warning | Detalhes Técnicos
|
||||
|
||||
Evite mutar diretamente `router.routes` após incluir um router. O FastAPI trata a inclusão de routers como algo ativo, então o router original e suas rotas permanecem parte do roteamento e da geração do OpenAPI.
|
||||
|
||||
Use APIs documentadas como os decoradores de operações de rota e `.include_router()` para adicionar rotas e routers.
|
||||
|
||||
Trate `router.routes` como uma árvore de rotas de nível mais baixo que pode conter definições de rotas e routers incluídos, e evite depender dela como uma lista plana de operações de rota finais.
|
||||
|
||||
///
|
||||
|
||||
@@ -108,7 +108,7 @@ Por exemplo:
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
`Body` também possui todas as validações adicionais e metadados de parâmetros como em `Query`,`Path` e outras que você verá depois.
|
||||
|
||||
@@ -123,7 +123,7 @@ Por padrão, o **FastAPI** esperará que seu conteúdo venha no corpo diretament
|
||||
Mas se você quiser que ele espere por um JSON com uma chave `item` e dentro dele os conteúdos do modelo, como ocorre ao declarar vários parâmetros de corpo, você pode usar o parâmetro especial de `Body` chamado `embed`:
|
||||
|
||||
```Python
|
||||
item: Item = Body(embed=True)
|
||||
item: Annotated[Item, Body(embed=True)]
|
||||
```
|
||||
|
||||
como em:
|
||||
|
||||
@@ -8,7 +8,7 @@ Você pode definir um atributo como um subtipo. Por exemplo, uma `list` do Pytho
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}
|
||||
|
||||
Isso fará com que tags seja uma lista de itens mesmo sem declarar o tipo dos elementos desta lista.
|
||||
Isso fará com que `tags` seja uma lista, mesmo sem declarar o tipo dos elementos desta lista.
|
||||
|
||||
## Campos do tipo Lista com um parâmetro de tipo { #list-fields-with-type-parameter }
|
||||
|
||||
@@ -53,7 +53,7 @@ Cada atributo de um modelo Pydantic tem um tipo.
|
||||
|
||||
Mas esse tipo pode ser outro modelo Pydantic.
|
||||
|
||||
Portanto, você pode declarar "objects" JSON profundamente aninhados com nomes, tipos e validações de atributos específicos.
|
||||
Portanto, você pode declarar "objetos" JSON profundamente aninhados com nomes, tipos e validações de atributos específicos.
|
||||
|
||||
Tudo isso, aninhado arbitrariamente.
|
||||
|
||||
@@ -69,7 +69,7 @@ E então podemos usá-lo como o tipo de um atributo:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}
|
||||
|
||||
Isso significa que o **FastAPI** vai esperar um corpo similar à:
|
||||
Isso significa que o **FastAPI** vai esperar um corpo similar a:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -98,11 +98,11 @@ Além dos tipos singulares normais como `str`, `int`, `float`, etc. Você també
|
||||
|
||||
Para ver todas as opções possíveis, consulte a [Visão geral dos tipos do Pydantic](https://docs.pydantic.dev/latest/concepts/types/). Você verá alguns exemplos no próximo capítulo.
|
||||
|
||||
Por exemplo, no modelo `Image` nós temos um campo `url`, nós podemos declará-lo como um `HttpUrl` do Pydantic invés de como uma `str`:
|
||||
Por exemplo, no modelo `Image` nós temos um campo `url`, nós podemos declará-lo como um `HttpUrl` do Pydantic em vez de como uma `str`:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}
|
||||
|
||||
A string será verificada para se tornar uma URL válida e documentada no JSON Schema / OpenAPI como tal.
|
||||
A string será verificada para ser uma URL válida e documentada no JSON Schema / OpenAPI como tal.
|
||||
|
||||
## Atributos como listas de submodelos { #attributes-with-lists-of-submodels }
|
||||
|
||||
@@ -136,7 +136,7 @@ Isso vai esperar (converter, validar, documentar, etc) um corpo JSON tal qual:
|
||||
}
|
||||
```
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Observe como a chave `images` agora tem uma lista de objetos de imagem.
|
||||
|
||||
@@ -148,7 +148,7 @@ Você pode definir modelos profundamente aninhados de forma arbitrária:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Observe como `Offer` tem uma lista de `Item`s, que por sua vez têm uma lista opcional de `Image`s
|
||||
|
||||
@@ -156,7 +156,7 @@ Observe como `Offer` tem uma lista de `Item`s, que por sua vez têm uma lista op
|
||||
|
||||
## Corpos de listas puras { #bodies-of-pure-lists }
|
||||
|
||||
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:
|
||||
Se o valor de primeiro nível do corpo JSON que você espera for um `array` do JSON (uma `list` 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]
|
||||
@@ -188,11 +188,11 @@ 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`.
|
||||
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`:
|
||||
Neste caso, você aceitaria qualquer `dict`, desde que tenha chaves `int` com valores `float`:
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}
|
||||
|
||||
@@ -204,7 +204,7 @@ 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`.
|
||||
E o `dict` que você recebe como `weights` terá, na verdade, chaves `int` e valores `float`.
|
||||
|
||||
///
|
||||
|
||||
@@ -215,7 +215,7 @@ Com **FastAPI** você tem a flexibilidade máxima fornecida pelos modelos Pydant
|
||||
Mas com todos os benefícios:
|
||||
|
||||
* Suporte do editor (preenchimento automático em todo canto!)
|
||||
* Conversão de dados (parsing/serialização)
|
||||
* Conversão de dados (também conhecido como parsing / serialização)
|
||||
* Validação de dados
|
||||
* Documentação dos esquemas
|
||||
* Documentação automática
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Corpo da requisição { #request-body }
|
||||
|
||||
|
||||
Quando você precisa enviar dados de um cliente (como de um navegador) para sua API, você os envia como um **corpo da requisição**.
|
||||
|
||||
O corpo da **requisição** é a informação enviada pelo cliente para sua API. O corpo da **resposta** é a informação que sua API envia para o cliente.
|
||||
@@ -8,7 +9,7 @@ Sua API quase sempre precisa enviar um corpo na **resposta**. Mas os clientes n
|
||||
|
||||
Para declarar um corpo da **requisição**, você utiliza os modelos do [Pydantic](https://docs.pydantic.dev/) com todos os seus poderes e benefícios.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Para enviar dados, você deveria usar um dos: `POST` (o mais comum), `PUT`, `DELETE` ou `PATCH`.
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ Você pode ver os cookies definidos na IU da documentação em `/docs`:
|
||||
<img src="/img/tutorial/cookie-param-models/image01.png">
|
||||
</div>
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Tenha em mente que, como os **navegadores lidam com cookies** de maneira especial e por baixo dos panos, eles **não** permitem facilmente que o **JavaScript** lidem com eles.
|
||||
|
||||
|
||||
@@ -24,13 +24,13 @@ Mas lembre-se que quando você importa `Query`, `Path`, `Cookie` e outras de `fa
|
||||
|
||||
///
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Para declarar cookies, você precisa usar `Cookie`, pois caso contrário, os parâmetros seriam interpretados como parâmetros de consulta.
|
||||
|
||||
///
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Tenha em mente que, como os **navegadores lidam com cookies** de maneiras especiais e nos bastidores, eles **não** permitem facilmente que o **JavaScript** os acesse.
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ Veja como pode parecer:
|
||||
|
||||
---
|
||||
|
||||
Se você usar o Pycharm, você pode:
|
||||
Se você usar o PyCharm, você pode:
|
||||
|
||||
* Abrir o menu "Executar".
|
||||
* Selecionar a opção "Depurar...".
|
||||
|
||||
@@ -28,7 +28,7 @@ Isso também pode ser útil para evitar confundir novos desenvolvedores que ao v
|
||||
|
||||
///
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Neste exemplo utilizamos cabeçalhos personalizados inventados `X-Key` e `X-Token`.
|
||||
|
||||
|
||||
@@ -115,15 +115,15 @@ Se você quiser capturar exceções e criar uma resposta personalizada com base
|
||||
|
||||
## Dependências com `yield` e `except` { #dependencies-with-yield-and-except }
|
||||
|
||||
Se você capturar uma exceção com `except` em uma dependência que utilize `yield` e ela não for levantada novamente (ou uma nova exceção for levantada), o FastAPI não será capaz de identificar que houve uma exceção, da mesma forma que aconteceria com Python puro:
|
||||
Se você capturar uma exceção com `except` em uma dependência que utilize `yield` e não a levantar novamente (nem levantar uma nova exceção), o FastAPI não será capaz de identificar que houve uma exceção, da mesma forma que aconteceria com Python puro:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}
|
||||
|
||||
Neste caso, o cliente irá ver uma resposta *HTTP 500 Internal Server Error* como deveria acontecer, já que não estamos levantando nenhuma `HTTPException` ou coisa parecida, mas o servidor **não terá nenhum log** ou qualquer outra indicação de qual foi o erro. 😱
|
||||
|
||||
### Sempre levante (`raise`) em Dependências com `yield` e `except` { #always-raise-in-dependencies-with-yield-and-except }
|
||||
### Sempre `raise` em Dependências com `yield` e `except` { #always-raise-in-dependencies-with-yield-and-except }
|
||||
|
||||
Se você capturar uma exceção em uma dependência com `yield`, a menos que você esteja levantando outra `HTTPException` ou coisa parecida, **você deve relançar a exceção original**.
|
||||
Se você capturar uma exceção em uma dependência com `yield`, a menos que você esteja levantando outra `HTTPException` ou coisa parecida, **você deveria relançar a exceção original**.
|
||||
|
||||
Você pode relançar a mesma exceção utilizando `raise`:
|
||||
|
||||
@@ -170,7 +170,7 @@ participant tasks as Tarefas de Background
|
||||
end
|
||||
```
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Apenas **uma resposta** será enviada para o cliente. Ela pode ser uma das respostas de erro, ou então a resposta da *operação de rota*.
|
||||
|
||||
@@ -194,7 +194,7 @@ Mas se você sabe que não precisará usar a dependência depois de retornar da
|
||||
|
||||
`Depends()` recebe um parâmetro `scope` que pode ser:
|
||||
|
||||
* `"function"`: iniciar a dependência antes da *função de operação de rota* que trata a requisição, encerrar a dependência depois que a *função de operação de rota* termina, mas **antes** de a resposta ser enviada de volta ao cliente. Assim, a função da dependência será executada **em torno** da *função de operação de rota*.
|
||||
* `"function"`: iniciar a dependência antes da *função de operação de rota* que trata a requisição, encerrar a dependência depois que a *função de operação de rota* termina, mas **antes** de a resposta ser enviada de volta ao cliente. Assim, a função da dependência será executada **em torno** da ***função*** *de operação de rota*.
|
||||
* `"request"`: iniciar a dependência antes da *função de operação de rota* que trata a requisição (semelhante a quando se usa `"function"`), mas encerrar **depois** que a resposta é enviada de volta ao cliente. Assim, a função da dependência será executada **em torno** do ciclo de **requisição** e resposta.
|
||||
|
||||
Se não for especificado e a dependência tiver `yield`, ela terá `scope` igual a `"request"` por padrão.
|
||||
@@ -234,6 +234,7 @@ participant operation as Operação de Rota
|
||||
Dependências com `yield` evoluíram ao longo do tempo para cobrir diferentes casos de uso e corrigir alguns problemas.
|
||||
|
||||
Se você quiser ver o que mudou em diferentes versões do FastAPI, você pode ler mais sobre isso no guia avançado, em [Dependências Avançadas - Dependências com `yield`, `HTTPException`, `except` e Tarefas de Background](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks).
|
||||
|
||||
## Gerenciadores de contexto { #context-managers }
|
||||
|
||||
### O que são "Gerenciadores de Contexto" { #what-are-context-managers }
|
||||
|
||||
@@ -51,7 +51,7 @@ Neste caso, a dependência espera por:
|
||||
|
||||
E então retorna um `dict` contendo esses valores.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
FastAPI passou a suportar a notação `Annotated` (e começou a recomendá-la) na versão 0.95.0.
|
||||
|
||||
@@ -106,7 +106,7 @@ common_parameters --> read_users
|
||||
|
||||
Assim, você escreve um código compartilhado apenas uma vez e o **FastAPI** se encarrega de chamá-lo em suas *operações de rota*.
|
||||
|
||||
/// check | Verifique
|
||||
/// tip | Dica
|
||||
|
||||
Perceba que você não precisa criar uma classe especial e enviar a dependência para algum outro lugar em que o **FastAPI** a "registre" ou realize qualquer operação similar.
|
||||
|
||||
@@ -136,7 +136,7 @@ Mas como o **FastAPI** se baseia em convenções do Python, incluindo `Annotated
|
||||
|
||||
///
|
||||
|
||||
As dependências continuarão funcionando como esperado, e a **melhor parte** é que a **informação sobre o tipo é preservada**, o que signfica que seu editor de texto ainda irá incluir **preenchimento automático**, **visualização de erros**, etc. O mesmo vale para ferramentas como `mypy`.
|
||||
As dependências continuarão funcionando como esperado, e a **melhor parte** é que a **informação sobre o tipo é preservada**, o que significa que seu editor de texto ainda irá incluir **preenchimento automático**, **erros em linha**, etc. O mesmo vale para ferramentas como `mypy`.
|
||||
|
||||
Isso é especialmente útil para uma **base de código grande** onde **as mesmas dependências** são utilizadas repetidamente em **muitas *operações de rota***.
|
||||
|
||||
@@ -152,7 +152,7 @@ Não faz diferença. O **FastAPI** sabe o que fazer.
|
||||
|
||||
/// note | Nota
|
||||
|
||||
Caso você não conheça, veja em [Async: *"Com Pressa?"*](../../async.md#in-a-hurry) a sessão acerca de `async` e `await` na documentação.
|
||||
Caso você não conheça, veja em [Async: *"Com Pressa?"*](../../async.md#in-a-hurry) a seção acerca de `async` e `await` na documentação.
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ Então podemos utilizar a dependência com:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Perceba que nós estamos declarando apenas uma dependência na *função de operação de rota*, em `query_or_cookie_extractor`.
|
||||
|
||||
|
||||
@@ -36,19 +36,19 @@ Aqui estão alguns dos tipos de dados adicionais que você pode usar:
|
||||
* `datetime.timedelta`:
|
||||
* O `datetime.timedelta` do Python.
|
||||
* Em requisições e respostas será representado como um `float` de segundos totais.
|
||||
* O Pydantic também permite representá-lo como uma "codificação ISO 8601 diferença de tempo", [cheque a documentação para mais informações](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).
|
||||
* O Pydantic também permite representá-lo como uma "codificação de diferença de tempo ISO 8601", [veja a documentação para mais informações](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).
|
||||
* `frozenset`:
|
||||
* Em requisições e respostas, será tratado da mesma forma que um `set`:
|
||||
* Nas requisições, uma lista será lida, eliminando duplicadas e convertendo-a em um `set`.
|
||||
* Nas requisições, uma list será lida, eliminando duplicadas e convertendo-a em um `set`.
|
||||
* Nas respostas, o `set` será convertido para uma `list`.
|
||||
* O esquema gerado vai especificar que os valores do `set` são únicos (usando o `uniqueItems` do JSON Schema).
|
||||
* `bytes`:
|
||||
* O `bytes` padrão do Python.
|
||||
* Em requisições e respostas será representado como uma `str`.
|
||||
* Em requisições e respostas será tratado como `str`.
|
||||
* O esquema gerado vai especificar que é uma `str` com o "formato" `binary`.
|
||||
* `Decimal`:
|
||||
* O `Decimal` padrão do Python.
|
||||
* Em requisições e respostas será representado como um `float`.
|
||||
* Em requisições e respostas, tratado da mesma forma que um `float`.
|
||||
* Você pode checar todos os tipos de dados válidos do Pydantic aqui: [Tipos de dados do Pydantic](https://docs.pydantic.dev/latest/usage/types/types/).
|
||||
|
||||
## Exemplo { #example }
|
||||
|
||||
@@ -208,4 +208,4 @@ Neste caso, você pode usar `dict`:
|
||||
|
||||
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.
|
||||
Não é necessário ter um único modelo de dados por entidade se essa entidade precisar ter diferentes "estados". A "entidade" **usuário** é um exemplo, com estados que incluem `password`, `password_hash` ou sem senha.
|
||||
|
||||
@@ -84,31 +84,31 @@ Você verá a documentação alternativa automática (fornecida por [ReDoc](http
|
||||
|
||||
### OpenAPI { #openapi }
|
||||
|
||||
O **FastAPI** gera um "*schema*" com toda a sua API usando o padrão **OpenAPI** para definir APIs.
|
||||
O **FastAPI** gera um "schema" com toda a sua API usando o padrão **OpenAPI** para definir APIs.
|
||||
|
||||
#### "*Schema*" { #schema }
|
||||
#### "Schema" { #schema }
|
||||
|
||||
Um "*schema*" é uma definição ou descrição de algo. Não o código que o implementa, mas apenas uma descrição abstrata.
|
||||
Um "schema" é uma definição ou descrição de algo. Não o código que o implementa, mas apenas uma descrição abstrata.
|
||||
|
||||
#### API "*schema*" { #api-schema }
|
||||
#### API "schema" { #api-schema }
|
||||
|
||||
Nesse caso, [OpenAPI](https://github.com/OAI/OpenAPI-Specification) é uma especificação que determina como definir um *schema* da sua API.
|
||||
Nesse caso, [OpenAPI](https://github.com/OAI/OpenAPI-Specification) é uma especificação que determina como definir um schema da sua API.
|
||||
|
||||
Esta definição de *schema* inclui os paths da sua API, os parâmetros possíveis que eles usam, etc.
|
||||
Esta definição de schema inclui os paths da sua API, os parâmetros possíveis que eles usam, etc.
|
||||
|
||||
#### "*Schema*" de dados { #data-schema }
|
||||
#### "Schema" de dados { #data-schema }
|
||||
|
||||
O termo "*schema*" também pode se referir à forma de alguns dados, como um conteúdo JSON.
|
||||
O termo "schema" também pode se referir à forma de alguns dados, como um conteúdo JSON.
|
||||
|
||||
Nesse caso, significaria os atributos JSON e os tipos de dados que eles possuem, etc.
|
||||
|
||||
#### OpenAPI e JSON Schema { #openapi-and-json-schema }
|
||||
|
||||
OpenAPI define um *schema* de API para sua API. E esse *schema* inclui definições (ou "*schemas*") dos dados enviados e recebidos por sua API usando **JSON Schema**, o padrão para *schemas* de dados JSON.
|
||||
OpenAPI define um schema de API para sua API. E esse schema inclui definições (ou "schemas") dos dados enviados e recebidos por sua API usando **JSON Schema**, o padrão para schemas de dados JSON.
|
||||
|
||||
#### Verifique o `openapi.json` { #check-the-openapi-json }
|
||||
|
||||
Se você está curioso(a) sobre a aparência do *schema* bruto OpenAPI, o FastAPI gera automaticamente um JSON (*schema*) com as descrições de toda a sua API.
|
||||
Se você está curioso(a) sobre a aparência do schema bruto OpenAPI, o FastAPI gera automaticamente um JSON (schema) com as descrições de toda a sua API.
|
||||
|
||||
Você pode ver isso diretamente em: [http://127.0.0.1:8000/openapi.json](http://127.0.0.1:8000/openapi.json).
|
||||
|
||||
@@ -137,11 +137,11 @@ Ele mostrará um JSON começando com algo como:
|
||||
|
||||
#### Para que serve o OpenAPI { #what-is-openapi-for }
|
||||
|
||||
O *schema* OpenAPI é o que possibilita os dois sistemas de documentação interativos mostrados.
|
||||
O schema OpenAPI é o que possibilita os dois sistemas de documentação interativos mostrados.
|
||||
|
||||
E existem dezenas de alternativas, todas baseadas em OpenAPI. Você pode facilmente adicionar qualquer uma dessas alternativas à sua aplicação criada com **FastAPI**.
|
||||
|
||||
Você também pode usá-lo para gerar código automaticamente para clientes que se comunicam com sua API. Por exemplo, aplicativos front-end, móveis ou IoT.
|
||||
Você também pode usá-lo para gerar código automaticamente para clientes que se comunicam com sua API. Por exemplo, aplicações frontend, móveis ou IoT.
|
||||
|
||||
### Configure o `entrypoint` da aplicação em `pyproject.toml` { #configure-the-app-entrypoint-in-pyproject-toml }
|
||||
|
||||
@@ -180,7 +180,7 @@ o que seria equivalente a:
|
||||
from backend.main import app
|
||||
```
|
||||
|
||||
### `fastapi dev` com path { #fastapi-dev-with-path }
|
||||
### `fastapi dev` com path ou com a opção de CLI `--entrypoint` { #fastapi-dev-with-path-or-with-entrypoint-cli-option }
|
||||
|
||||
Você também pode passar o path do arquivo para o comando `fastapi dev`, e ele vai deduzir o objeto de aplicação FastAPI a ser usado:
|
||||
|
||||
@@ -188,29 +188,19 @@ Você também pode passar o path do arquivo para o comando `fastapi dev`, e ele
|
||||
$ fastapi dev main.py
|
||||
```
|
||||
|
||||
Mas você teria que lembrar de passar o path correto toda vez que chamar o comando `fastapi`.
|
||||
Ou você também pode passar a opção `--entrypoint` para o comando `fastapi dev`:
|
||||
|
||||
```console
|
||||
$ fastapi dev --entrypoint main:app
|
||||
```
|
||||
|
||||
Mas você teria que lembrar de passar o path\entrypoint correto toda vez que chamar o comando `fastapi`.
|
||||
|
||||
Além disso, outras ferramentas podem não conseguir encontrá-la, por exemplo, a [Extensão do VS Code](../editor-support.md) ou a [FastAPI Cloud](https://fastapicloud.com), então é recomendado usar o `entrypoint` no `pyproject.toml`.
|
||||
|
||||
### Faça o deploy da sua aplicação (opcional) { #deploy-your-app-optional }
|
||||
|
||||
Você pode, opcionalmente, fazer o deploy da sua aplicação FastAPI na [FastAPI Cloud](https://fastapicloud.com); acesse e entre na lista de espera, se ainda não entrou. 🚀
|
||||
|
||||
Se você já tem uma conta na **FastAPI Cloud** (nós convidamos você da lista de espera 😉), pode fazer o deploy da sua aplicação com um único comando.
|
||||
|
||||
Antes do deploy, certifique-se de que está autenticado:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi login
|
||||
|
||||
You are logged in to FastAPI Cloud 🚀
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Em seguida, faça o deploy da sua aplicação:
|
||||
Você pode, opcionalmente, fazer o deploy da sua aplicação FastAPI na [FastAPI Cloud](https://fastapicloud.com) com um único comando. 🚀
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -226,6 +216,8 @@ Deploying to FastAPI Cloud...
|
||||
|
||||
</div>
|
||||
|
||||
A CLI detectará automaticamente sua aplicação FastAPI e a fará o deploy na nuvem. Se você não estiver autenticado, o seu navegador será aberto para concluir o processo de autenticação.
|
||||
|
||||
É isso! Agora você pode acessar sua aplicação nessa URL. ✨
|
||||
|
||||
## Recapitulando, passo a passo { #recap-step-by-step }
|
||||
@@ -252,7 +244,7 @@ Aqui, a variável `app` será uma "instância" da classe `FastAPI`.
|
||||
|
||||
Este será o principal ponto de interação para criar toda a sua API.
|
||||
|
||||
### Passo 3: crie uma operação de rota { #step-3-create-a-path-operation }
|
||||
### Passo 3: crie uma *operação de rota* { #step-3-create-a-path-operation }
|
||||
|
||||
#### Path { #path }
|
||||
|
||||
@@ -270,7 +262,7 @@ https://example.com/items/foo
|
||||
/items/foo
|
||||
```
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Um "path" também é comumente chamado de "endpoint" ou de "rota".
|
||||
|
||||
@@ -313,16 +305,16 @@ Portanto, no OpenAPI, cada um dos métodos HTTP é chamado de "operação".
|
||||
|
||||
Vamos chamá-los de "**operações**" também.
|
||||
|
||||
#### Defina um decorador de operação de rota { #define-a-path-operation-decorator }
|
||||
#### Defina um *decorador de operação de rota* { #define-a-path-operation-decorator }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}
|
||||
|
||||
O `@app.get("/")` diz ao **FastAPI** que a função logo abaixo é responsável por tratar as requisições que vão para:
|
||||
|
||||
* o path `/`
|
||||
* usando uma <dfn title="um método HTTP GET"><code>get</code> operação</dfn>
|
||||
* usando uma <dfn title="um método HTTP GET">operação <code>get</code></dfn>
|
||||
|
||||
/// info | Informações sobre `@decorator`
|
||||
/// note | Informações sobre `@decorator`
|
||||
|
||||
Essa sintaxe `@alguma_coisa` em Python é chamada de "decorador".
|
||||
|
||||
@@ -395,7 +387,7 @@ Se você não sabe a diferença, verifique o [Async: *"Com pressa?"*](../async.m
|
||||
|
||||
Você pode retornar um `dict`, `list` e valores singulares como `str`, `int`, etc.
|
||||
|
||||
Você também pode devolver modelos Pydantic ( você verá mais sobre isso mais tarde).
|
||||
Você também pode retornar modelos Pydantic (você verá mais sobre isso mais tarde).
|
||||
|
||||
Existem muitos outros objetos e modelos que serão convertidos automaticamente para JSON (incluindo ORMs, etc). Tente usar seus favoritos, é altamente provável que já sejam compatíveis.
|
||||
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
# Frontend { #frontend }
|
||||
|
||||
Você pode servir aplicações frontend estáticas com `app.frontend()` ou `router.frontend()`.
|
||||
|
||||
Isso é útil para ferramentas de frontend que geram arquivos estáticos, como React com Vite, TanStack Router, Astro, Vue, Svelte, Angular, Solid e outras.
|
||||
|
||||
Com essas ferramentas, normalmente há uma etapa que faz o build do frontend, com um comando como:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
Isso geraria um diretório como `./dist/` com seus arquivos de frontend.
|
||||
|
||||
Você pode usar `app.frontend()` para servir esse diretório seguindo as convenções necessárias por esses frameworks de frontend.
|
||||
|
||||
**FastAPI** verifica as *operações de rota* primeiro. Os arquivos de frontend são verificados somente se nenhuma rota normal corresponder, então sua API não será afetada.
|
||||
|
||||
## Sirva um Frontend { #serve-a-frontend }
|
||||
|
||||
Depois de fazer o build do seu frontend, por exemplo com `npm run build`, coloque os arquivos gerados em um diretório, por exemplo, `dist`.
|
||||
|
||||
A estrutura do seu projeto poderia ser assim:
|
||||
|
||||
```text
|
||||
.
|
||||
├── pyproject.toml
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ └── main.py
|
||||
└── dist
|
||||
├── index.html
|
||||
└── assets
|
||||
└── app.js
|
||||
```
|
||||
|
||||
Então sirva-o com `app.frontend()`:
|
||||
|
||||
{* ../../docs_src/frontend/tutorial001_py310.py hl[5] *}
|
||||
|
||||
Com isso, um request para `/assets/app.js` pode servir `dist/assets/app.js`.
|
||||
|
||||
Se você também tiver uma *operação de rota* do **FastAPI**, a *operação de rota* tem prioridade.
|
||||
|
||||
## Roteamento no Lado do Cliente { #client-side-routing }
|
||||
|
||||
Muitas aplicações frontend, incluindo **aplicações de página única** (SPAs), usam roteamento no lado do cliente. Um path como `/dashboard/settings` pode não ser um arquivo real, mas o framework cuidaria de lidar com ele.
|
||||
|
||||
Então, ao acessar essa URL diretamente (em vez de navegar pela aplicação), o backend deveria servir a aplicação frontend a partir de `index.html`, para que o framework de frontend possa então lidar com o roteamento no lado do cliente.
|
||||
|
||||
Para isso, use `fallback="index.html"`:
|
||||
|
||||
{* ../../docs_src/frontend/tutorial002_py310.py hl[5] *}
|
||||
|
||||
**FastAPI** usa esse fallback somente para requests `GET` e `HEAD` que parecem navegação do navegador. Arquivos ausentes como JavaScript, CSS e imagens ainda retornam `404`.
|
||||
|
||||
Requests com outros métodos, como `POST` ou `PUT`, para paths que correspondem apenas ao fallback do frontend também retornam `404`. *Operações de rota* regulares do **FastAPI** ainda têm prioridade maior que rotas de frontend.
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Por padrão, `fallback` tem o valor `fallback="auto"`. Na maioria dos casos, você não precisará especificar `fallback`. Leia abaixo para detalhes.
|
||||
|
||||
///
|
||||
|
||||
Isso é o que você desejaria com muitas aplicações frontend que usam roteamento no lado do cliente, por exemplo, React com TanStack Router, Vue, Angular, SvelteKit ou Solid.
|
||||
|
||||
## Página 404 Personalizada { #custom-404-page }
|
||||
|
||||
Você também pode servir uma página estática `404.html` para paths de frontend ausentes:
|
||||
|
||||
{* ../../docs_src/frontend/tutorial003_py310.py hl[5] *}
|
||||
|
||||
Essa response mantém um código de status `404`.
|
||||
|
||||
Neste caso, **FastAPI** não servirá `index.html` para paths de frontend ausentes. Ele retornará o arquivo `404.html` em vez disso.
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Por padrão, `fallback` tem o valor `fallback="auto"`. Com isso, se um arquivo `404.html` for encontrado, ele será usado automaticamente como fallback.
|
||||
|
||||
Então, normalmente você pode omitir o argumento `fallback`.
|
||||
|
||||
///
|
||||
|
||||
Isso é útil com ferramentas de frontend que geram arquivos HTML estáticos para cada página, como Astro.
|
||||
|
||||
## Fallback Automático { #fallback-auto }
|
||||
|
||||
Por padrão, `app.frontend()` usa `fallback="auto"`.
|
||||
|
||||
Se houver um arquivo `404.html` no diretório do frontend, paths de frontend ausentes servem esse arquivo com código de status `404`.
|
||||
|
||||
Caso contrário, se houver um arquivo `index.html`, paths de navegação do navegador ausentes servem `index.html`, que é o que muitas aplicações frontend com roteamento no lado do cliente esperam.
|
||||
|
||||
Então, na maioria dos casos, você pode usar `app.frontend("/", directory="dist")` sem especificar o argumento `fallback`.
|
||||
|
||||
{* ../../docs_src/frontend/tutorial001_py310.py hl[5] *}
|
||||
|
||||
## Desative o Fallback { #disable-fallback }
|
||||
|
||||
Se você não quiser servir um arquivo de fallback para paths de frontend ausentes, use `fallback=None`:
|
||||
|
||||
{* ../../docs_src/frontend/tutorial005_py310.py hl[5] *}
|
||||
|
||||
Então paths de frontend ausentes retornam o `404` normal.
|
||||
|
||||
## Verifique o Diretório { #check-directory }
|
||||
|
||||
Por padrão, `app.frontend()` verifica se o diretório existe quando a aplicação é criada.
|
||||
|
||||
Isso ajuda a identificar erros de configuração cedo. Por exemplo, se o diretório de saída do build do frontend estiver ausente, **FastAPI** gerará um erro na inicialização.
|
||||
|
||||
Se seus arquivos de frontend forem criados depois, por exemplo por uma etapa de build separada após o objeto da aplicação ser criado, defina `check_dir=False`:
|
||||
|
||||
{* ../../docs_src/frontend/tutorial006_py310.py hl[5] *}
|
||||
|
||||
Com `check_dir=False`, **FastAPI** não verificará o diretório quando a aplicação for criada. Se o diretório configurado ainda estiver ausente quando um request for processado, **FastAPI** gerará um erro nesse momento.
|
||||
|
||||
## Use com `APIRouter` { #use-it-with-apirouter }
|
||||
|
||||
Você também pode adicionar arquivos de frontend a um `APIRouter` e incluí-lo com um prefixo:
|
||||
|
||||
{* ../../docs_src/frontend/tutorial004_py310.py hl[6,7] *}
|
||||
|
||||
Neste exemplo, os paths de frontend são servidos em `/app`.
|
||||
|
||||
Quaisquer *operações de rota* regulares na aplicação ainda terão precedência, inclusive em outros routers.
|
||||
|
||||
## Apenas Saída de Build Estático { #static-build-output-only }
|
||||
|
||||
`app.frontend()` serve arquivos já gerados pelo build do seu frontend.
|
||||
|
||||
Ele não executa renderização no lado do servidor. Ele é para frameworks de frontend que geram arquivos estáticos, não para frameworks que precisam de renderização dinâmica no servidor para cada request.
|
||||
@@ -6,45 +6,44 @@ Esse cliente pode ser um browser com um frontend, o código de outra pessoa, um
|
||||
|
||||
Pode ser que você precise comunicar ao cliente que:
|
||||
|
||||
* O cliente não tem direitos para realizar aquela operação.
|
||||
* O cliente não tem privilégios suficientes para aquela operação.
|
||||
* O cliente não tem acesso aquele recurso.
|
||||
* O item que o cliente está tentando acessar não existe.
|
||||
* O item que o cliente estava tentando acessar não existe.
|
||||
* etc.
|
||||
|
||||
Nesses casos, você normalmente retornaria um **HTTP status code** próximo ao status code na faixa do status code **400** (do 400 ao 499).
|
||||
Nesses casos, você normalmente retornaria um **HTTP status code** na faixa de **400** (do 400 ao 499).
|
||||
|
||||
Isso é bastante similar ao caso do HTTP status code 200 (do 200 ao 299). Esses "200" status codes significam que, de algum modo, houve sucesso na requisição.
|
||||
Isso é similar aos status codes HTTP 200 (do 200 ao 299). Esses status codes "200" significam que, de algum modo, houve um "sucesso" na request.
|
||||
|
||||
Os status codes na faixa dos 400 significam que houve um erro por parte do cliente.
|
||||
|
||||
Você se lembra de todos aqueles erros (e piadas) a respeito do "**404 Not Found**"?
|
||||
Você se lembra de todos aqueles erros **"404 Not Found"** (e piadas)?
|
||||
|
||||
## Use o `HTTPException` { #use-httpexception }
|
||||
|
||||
Para retornar ao cliente *responses* HTTP com erros, use o `HTTPException`.
|
||||
Para retornar responses HTTP com erros ao cliente, use o `HTTPException`.
|
||||
|
||||
### Import `HTTPException` { #import-httpexception }
|
||||
### Importe `HTTPException` { #import-httpexception }
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}
|
||||
|
||||
### Lance o `HTTPException` no seu código { #raise-an-httpexception-in-your-code }
|
||||
### Lance uma `HTTPException` no seu código { #raise-an-httpexception-in-your-code }
|
||||
|
||||
`HTTPException`, ao fundo, nada mais é do que a conjunção entre uma exceção comum do Python e informações adicionais relevantes para APIs.
|
||||
`HTTPException` é uma exceção normal do Python com dados adicionais relevantes para APIs.
|
||||
|
||||
E porque é uma exceção do Python, você não **retorna** (return) o `HTTPException`, você lança o (raise) no seu código.
|
||||
Como é uma exceção do Python, você não dá `return` nela, você dá `raise` nela.
|
||||
|
||||
Isso também significa que, se você está escrevendo uma função de utilidade, a qual você está chamando dentro da sua função de operação de rota, e você lança o `HTTPException` dentro da função de utilidade, o resto do seu código não será executado dentro da função de operação de rota. Ao contrário, o `HTTPException` irá finalizar a requisição no mesmo instante e enviará o erro HTTP oriundo do `HTTPException` para o cliente.
|
||||
Isso também significa que, se você está dentro de uma função de utilidade que está chamando dentro da sua *função de operação de rota*, e lança a `HTTPException` dentro dessa função de utilidade, o restante do código na *função de operação de rota* não será executado, a request será encerrada imediatamente e o erro HTTP da `HTTPException` será enviado ao cliente.
|
||||
|
||||
O benefício de lançar uma exceção em vez de retornar um valor ficará mais evidente na seção sobre Dependências e Segurança.
|
||||
|
||||
Neste exemplo, quando o cliente pede, na requisição, por um item cujo ID não existe, a exceção com o status code `404` é lançada:
|
||||
Neste exemplo, quando o cliente solicita um item por um ID que não existe, lance uma exceção com status code `404`:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}
|
||||
|
||||
### A response resultante { #the-resulting-response }
|
||||
|
||||
Se o cliente faz uma requisição para `http://example.com/items/foo` (um `item_id` `"foo"`), esse cliente receberá um HTTP status code 200, e uma resposta JSON:
|
||||
|
||||
Se o cliente solicita `http://example.com/items/foo` (um `item_id` `"foo"`), esse cliente receberá um status code HTTP 200 e uma response JSON de:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -52,7 +51,7 @@ Se o cliente faz uma requisição para `http://example.com/items/foo` (um `item_
|
||||
}
|
||||
```
|
||||
|
||||
Mas se o cliente faz uma requisição para `http://example.com/items/bar` (ou seja, um não existente `item_id "bar"`), esse cliente receberá um HTTP status code 404 (o erro "não encontrado" — *not found error*), e uma resposta JSON:
|
||||
Mas se o cliente solicita `http://example.com/items/bar` (um `item_id` `"bar"` inexistente), esse cliente receberá um status code HTTP 404 (o erro "not found") e uma response JSON de:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -62,38 +61,41 @@ Mas se o cliente faz uma requisição para `http://example.com/items/bar` (ou se
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Quando você lançar um `HTTPException`, você pode passar qualquer valor convertível em JSON como parâmetro de `detail`, e não apenas `str`.
|
||||
Ao lançar uma `HTTPException`, você pode passar qualquer valor que possa ser convertido para JSON como parâmetro `detail`, não apenas `str`.
|
||||
|
||||
Você pode passar um `dict` ou um `list`, etc.
|
||||
Esses tipos de dados são manipulados automaticamente pelo **FastAPI** e convertidos em JSON.
|
||||
Você pode passar um `dict`, uma `list`, etc.
|
||||
|
||||
Eles são manipulados automaticamente pelo **FastAPI** e convertidos para JSON.
|
||||
|
||||
///
|
||||
|
||||
## Adicione headers customizados { #add-custom-headers }
|
||||
|
||||
Há certas situações em que é bastante útil poder adicionar headers customizados no HTTP error. Exemplo disso seria adicionar headers customizados para tipos de segurança.
|
||||
Há algumas situações em que é útil poder adicionar headers customizados ao erro HTTP. Por exemplo, para alguns tipos de segurança.
|
||||
|
||||
Você provavelmente não precisará utilizar esses headers diretamente no seu código.
|
||||
Você provavelmente não precisará usar isso diretamente no seu código.
|
||||
|
||||
Mas caso você precise, para um cenário mais complexo, você pode adicionar headers customizados:
|
||||
Mas caso precise em um cenário avançado, você pode adicionar headers customizados:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}
|
||||
|
||||
## Instale manipuladores de exceções customizados { #install-custom-exception-handlers }
|
||||
|
||||
Você pode adicionar manipuladores de exceção customizados com [a mesma seção de utilidade de exceções presentes no Starlette](https://www.starlette.dev/exceptions/).
|
||||
Você pode adicionar manipuladores de exceção customizados com [as mesmas utilidades de exceção do Starlette](https://www.starlette.dev/exceptions/).
|
||||
|
||||
Digamos que você tenha uma exceção customizada `UnicornException` que você (ou uma biblioteca que você use) precise lançar (`raise`).
|
||||
Digamos que você tenha uma exceção customizada `UnicornException` que você (ou uma biblioteca que você usa) possa lançar com `raise`.
|
||||
|
||||
Nesse cenário, se você precisa manipular essa exceção de modo global com o FastAPI, você pode adicionar um manipulador de exceção customizada com `@app.exception_handler()`.
|
||||
E você quer manipular essa exceção globalmente com o FastAPI.
|
||||
|
||||
Você poderia adicionar um manipulador de exceção customizado com `@app.exception_handler()`:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}
|
||||
|
||||
Nesse cenário, se você fizer uma requisição para `/unicorns/yolo`, a *operação de rota* vai lançar (`raise`) o `UnicornException`.
|
||||
Aqui, se você fizer uma request para `/unicorns/yolo`, a *operação de rota* vai lançar com `raise` uma `UnicornException`.
|
||||
|
||||
Essa exceção será manipulada, contudo, pelo `unicorn_exception_handler`.
|
||||
Mas ela será manipulada pelo `unicorn_exception_handler`.
|
||||
|
||||
Dessa forma você receberá um erro "limpo", com o HTTP status code `418` e um JSON com o conteúdo:
|
||||
Assim, você receberá um erro limpo, com um status code HTTP `418` e um conteúdo JSON de:
|
||||
|
||||
```JSON
|
||||
{"message": "Oops! yolo did something. There goes a rainbow..."}
|
||||
@@ -103,7 +105,7 @@ Dessa forma você receberá um erro "limpo", com o HTTP status code `418` e um J
|
||||
|
||||
Você também pode usar `from starlette.requests import Request` e `from starlette.responses import JSONResponse`.
|
||||
|
||||
**FastAPI** disponibiliza o mesmo `starlette.responses` através do `fastapi.responses` por conveniência ao desenvolvedor. Contudo, a maior parte das respostas disponíveis vem diretamente do Starlette. O mesmo acontece com o `Request`.
|
||||
**FastAPI** fornece o mesmo `starlette.responses` como `fastapi.responses` apenas como uma conveniência para você, a pessoa desenvolvedora. Mas a maior parte das responses disponíveis vem diretamente do Starlette. O mesmo acontece com `Request`.
|
||||
|
||||
///
|
||||
|
||||
@@ -111,23 +113,23 @@ Você também pode usar `from starlette.requests import Request` e `from starlet
|
||||
|
||||
**FastAPI** tem alguns manipuladores padrão de exceções.
|
||||
|
||||
Esses manipuladores são os responsáveis por retornar o JSON padrão de respostas quando você lança (`raise`) o `HTTPException` e quando a requisição tem dados inválidos.
|
||||
Esses manipuladores são responsáveis por retornar as responses JSON padrão quando você lança com `raise` uma `HTTPException` e quando a request tem dados inválidos.
|
||||
|
||||
Você pode sobrescrever esses manipuladores de exceção com os seus próprios manipuladores.
|
||||
Você pode sobrescrever esses manipuladores de exceção com os seus próprios.
|
||||
|
||||
### Sobrescreva exceções de validação da requisição { #override-request-validation-exceptions }
|
||||
### Sobrescreva exceções de validação da request { #override-request-validation-exceptions }
|
||||
|
||||
Quando a requisição contém dados inválidos, **FastAPI** internamente lança para o `RequestValidationError`.
|
||||
Quando uma request contém dados inválidos, **FastAPI** internamente lança um `RequestValidationError`.
|
||||
|
||||
E também inclui um manipulador de exceções padrão para ele.
|
||||
|
||||
Para sobrescrevê-lo, importe o `RequestValidationError` e use-o com o `@app.exception_handler(RequestValidationError)` para decorar o manipulador de exceções.
|
||||
Para sobrescrevê-lo, importe o `RequestValidationError` e use-o com `@app.exception_handler(RequestValidationError)` para decorar o manipulador de exceções.
|
||||
|
||||
O manipulador de exceções receberá um `Request` e a exceção.
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}
|
||||
|
||||
Se você for ao `/items/foo`, em vez de receber o JSON padrão com o erro:
|
||||
Agora, se você for para `/items/foo`, em vez de receber o erro JSON padrão com:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -144,7 +146,7 @@ Se você for ao `/items/foo`, em vez de receber o JSON padrão com o erro:
|
||||
}
|
||||
```
|
||||
|
||||
você receberá a versão em texto:
|
||||
você receberá uma versão em texto, com:
|
||||
|
||||
```
|
||||
Validation errors:
|
||||
@@ -153,17 +155,17 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa
|
||||
|
||||
### Sobrescreva o manipulador de erro `HTTPException` { #override-the-httpexception-error-handler }
|
||||
|
||||
Do mesmo modo, você pode sobrescrever o `HTTPException`.
|
||||
Do mesmo modo, você pode sobrescrever o manipulador de `HTTPException`.
|
||||
|
||||
Por exemplo, você pode querer retornar uma *response* em *plain text* ao invés de um JSON para os seguintes erros:
|
||||
Por exemplo, você poderia querer retornar uma response em texto simples em vez de JSON para estes erros:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}
|
||||
|
||||
/// note | Detalhes Técnicos
|
||||
|
||||
Você pode usar `from starlette.responses import PlainTextResponse`.
|
||||
Você também pode usar `from starlette.responses import PlainTextResponse`.
|
||||
|
||||
**FastAPI** disponibiliza o mesmo `starlette.responses` como `fastapi.responses`, como conveniência a você, desenvolvedor. Contudo, a maior parte das respostas disponíveis vem diretamente do Starlette.
|
||||
**FastAPI** fornece o mesmo `starlette.responses` como `fastapi.responses` apenas como uma conveniência para você, a pessoa desenvolvedora. Mas a maior parte das responses disponíveis vem diretamente do Starlette.
|
||||
|
||||
///
|
||||
|
||||
@@ -171,19 +173,19 @@ Você pode usar `from starlette.responses import PlainTextResponse`.
|
||||
|
||||
Tenha em mente que o `RequestValidationError` contém as informações do nome do arquivo e da linha onde o erro de validação acontece, para que você possa mostrá-las nos seus logs com as informações relevantes, se quiser.
|
||||
|
||||
Mas isso significa que, se você simplesmente convertê-lo para uma string e retornar essa informação diretamente, você pode acabar vazando um pouco de informação sobre o seu sistema; por isso, aqui o código extrai e mostra cada erro de forma independente.
|
||||
Mas isso significa que, se você simplesmente convertê-lo para uma string e retornar essa informação diretamente, você poderia acabar vazando um pouco de informação sobre o seu sistema; por isso, aqui o código extrai e mostra cada erro de forma independente.
|
||||
|
||||
///
|
||||
|
||||
### Use o body do `RequestValidationError` { #use-the-requestvalidationerror-body }
|
||||
|
||||
O `RequestValidationError` contém o `body` que ele recebeu de dados inválidos.
|
||||
O `RequestValidationError` contém o `body` que ele recebeu com dados inválidos.
|
||||
|
||||
Você pode utilizá-lo enquanto desenvolve seu app para registrar o *body* e debugá-lo, e assim retorná-lo ao usuário, etc.
|
||||
Você poderia usá-lo enquanto desenvolve sua aplicação para registrar o body e depurá-lo, retorná-lo ao usuário, etc.
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}
|
||||
|
||||
Tente enviar um item inválido como este:
|
||||
Agora tente enviar um item inválido como:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -192,7 +194,7 @@ Tente enviar um item inválido como este:
|
||||
}
|
||||
```
|
||||
|
||||
Você receberá uma *response* informando-o de que os dados são inválidos, e contendo o *body* recebido:
|
||||
Você receberá uma response dizendo que os dados são inválidos contendo o body recebido:
|
||||
|
||||
```JSON hl_lines="12-15"
|
||||
{
|
||||
@@ -213,21 +215,21 @@ Você receberá uma *response* informando-o de que os dados são inválidos, e c
|
||||
}
|
||||
```
|
||||
|
||||
#### O `HTTPException` do FastAPI vs o `HTTPException` do Starlette { #fastapis-httpexception-vs-starlettes-httpexception }
|
||||
#### `HTTPException` do FastAPI vs `HTTPException` do Starlette { #fastapis-httpexception-vs-starlettes-httpexception }
|
||||
|
||||
O **FastAPI** tem o seu próprio `HTTPException`.
|
||||
**FastAPI** tem a sua própria `HTTPException`.
|
||||
|
||||
E a classe de erro `HTTPException` do **FastAPI** herda da classe de erro do `HTTPException` do Starlette.
|
||||
E a classe de erro `HTTPException` do **FastAPI** herda da classe de erro `HTTPException` do Starlette.
|
||||
|
||||
A única diferença é que o `HTTPException` do **FastAPI** aceita qualquer dado que possa ser convertido em JSON para o campo `detail`, enquanto o `HTTPException` do Starlette aceita apenas strings para esse campo.
|
||||
A única diferença é que a `HTTPException` do **FastAPI** aceita qualquer dado que possa ser convertido para JSON no campo `detail`, enquanto a `HTTPException` do Starlette aceita apenas strings para ele.
|
||||
|
||||
Portanto, você pode continuar lançando o `HTTPException` do **FastAPI** normalmente no seu código.
|
||||
Portanto, você pode continuar lançando a `HTTPException` do **FastAPI** normalmente no seu código.
|
||||
|
||||
Porém, quando você registrar um manipulador de exceção, você deve registrá-lo através do `HTTPException` do Starlette.
|
||||
Mas quando registrar um manipulador de exceção, você deveria registrá-lo para a `HTTPException` do Starlette.
|
||||
|
||||
Dessa forma, se qualquer parte do código interno, extensão ou plug-in do Starlette lançar um `HTTPException` do Starlette, o seu manipulador poderá capturar e tratá-lo.
|
||||
Dessa forma, se qualquer parte do código interno do Starlette, ou uma extensão ou plug-in do Starlette, lançar uma `HTTPException` do Starlette, seu manipulador poderá capturá-la e tratá-la.
|
||||
|
||||
Neste exemplo, para poder ter ambos os `HTTPException` no mesmo código, a exceção do Starlette é renomeada para `StarletteHTTPException`:
|
||||
Neste exemplo, para poder ter ambas as `HTTPException`s no mesmo código, a exceção do Starlette é renomeada para `StarletteHTTPException`:
|
||||
|
||||
```Python
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
@@ -235,8 +237,8 @@ from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
|
||||
### Reutilize os manipuladores de exceção do **FastAPI** { #reuse-fastapis-exception-handlers }
|
||||
|
||||
Se você quer usar a exceção em conjunto com o mesmo manipulador de exceção *default* do **FastAPI**, você pode importar e re-usar esses manipuladores de exceção do `fastapi.exception_handlers`:
|
||||
Se você quiser usar a exceção junto com os mesmos manipuladores de exceção padrão do **FastAPI**, você pode importar e reutilizar os manipuladores de exceção padrão de `fastapi.exception_handlers`:
|
||||
|
||||
{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}
|
||||
|
||||
Nesse exemplo você apenas imprime (`print`) o erro com uma mensagem expressiva. Mesmo assim, dá para pegar a ideia. Você pode usar a exceção e então apenas re-usar o manipulador de exceção *default*.
|
||||
Neste exemplo, você está apenas imprimindo o erro com uma mensagem muito expressiva, mas a ideia é essa. Você pode usar a exceção e então simplesmente reutilizar os manipuladores de exceção padrão.
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# Tutorial - Guia de Usuário { #tutorial-user-guide }
|
||||
|
||||
Esse tutorial mostra como usar o **FastAPI** com a maior parte de seus recursos, passo a passo.
|
||||
Este tutorial mostra como usar o **FastAPI** com a maior parte de seus recursos, passo a passo.
|
||||
|
||||
Cada seção constrói, gradualmente, sobre as anteriores, mas sua estrutura são tópicos separados, para que você possa ir a qualquer um específico e resolver suas necessidades específicas de API.
|
||||
|
||||
Ele também foi construído para servir como uma referência futura, então você pode voltar e ver exatamente o que você precisa.
|
||||
|
||||
## Rode o código { #run-the-code }
|
||||
## Execute o código { #run-the-code }
|
||||
|
||||
Todos os blocos de código podem ser copiados e utilizados diretamente (eles são, na verdade, arquivos Python testados).
|
||||
|
||||
Para rodar qualquer um dos exemplos, copie o código para um arquivo `main.py`, e inicie o `fastapi dev`:
|
||||
Para executar qualquer um dos exemplos, copie o código para um arquivo `main.py`, e inicie o `fastapi dev`:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -52,9 +52,9 @@ $ <font color="#4E9A06">fastapi</font> dev
|
||||
|
||||
</div>
|
||||
|
||||
É **ALTAMENTE recomendado** que você escreva ou copie o código, edite-o e rode-o localmente.
|
||||
É **ALTAMENTE recomendado** que você escreva ou copie o código, edite-o e execute-o localmente.
|
||||
|
||||
Usá-lo em seu editor é o que realmente te mostra os benefícios do FastAPI, ver quão pouco código você tem que escrever, todas as conferências de tipo, preenchimento automático, etc.
|
||||
Usá-lo em seu editor é o que realmente mostra os benefícios do FastAPI, vendo quão pouco código você tem que escrever, todas as verificações de tipo, preenchimento automático, etc.
|
||||
|
||||
---
|
||||
|
||||
@@ -94,7 +94,7 @@ O FastAPI tem uma [extensão oficial para o VS Code](https://marketplace.visuals
|
||||
|
||||
Há também um **Guia Avançado de Usuário** que você pode ler após esse **Tutorial - Guia de Usuário**.
|
||||
|
||||
O **Guia Avançado de Usuário** constrói sobre esse, usa os mesmos conceitos e te ensina algumas funcionalidades extras.
|
||||
O **Guia Avançado de Usuário** constrói sobre esse, usa os mesmos conceitos e ensina algumas funcionalidades extras.
|
||||
|
||||
Mas você deveria ler primeiro o **Tutorial - Guia de Usuário** (que você está lendo agora).
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ Você pode definir os seguintes campos que são usados na especificação OpenAP
|
||||
| `title` | `str` | O título da API. |
|
||||
| `summary` | `str` | Um breve resumo da API. <small>Disponível desde OpenAPI 3.1.0, FastAPI 0.99.0.</small> |
|
||||
| `description` | `str` | Uma breve descrição da API. Pode usar Markdown. |
|
||||
| `version` | `string` | A versão da API. Esta é a versão da sua aplicação, não do OpenAPI. Por exemplo, `2.5.0`. |
|
||||
| `version` | `str` | A versão da API. Esta é a versão da sua aplicação, não do OpenAPI. Por exemplo, `2.5.0`. |
|
||||
| `terms_of_service` | `str` | Uma URL para os Termos de Serviço da API. Se fornecido, deve ser uma URL. |
|
||||
| `contact` | `dict` | As informações de contato da API exposta. Pode conter vários campos. <details><summary>Campos de <code>contact</code></summary><table><thead><tr><th>Parâmetro</th><th>Tipo</th><th>Descrição</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>O nome identificador da pessoa/organização de contato.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>A URL que aponta para as informações de contato. DEVE estar no formato de uma URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>O endereço de e-mail da pessoa/organização de contato. DEVE estar no formato de um endereço de e-mail.</td></tr></tbody></table></details> |
|
||||
| `license_info` | `dict` | As informações de licença para a API exposta. Ela pode conter vários campos. <details><summary>Campos de <code>license_info</code></summary><table><thead><tr><th>Parâmetro</th><th>Tipo</th><th>Descrição</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>OBRIGATÓRIO</strong> (se um <code>license_info</code> for definido). O nome da licença usada para a API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>Uma expressão de licença [SPDX](https://spdx.org/licenses/) para a API. O campo <code>identifier</code> é mutuamente exclusivo do campo <code>url</code>. <small>Disponível desde OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>Uma URL para a licença usada para a API. DEVE estar no formato de uma URL.</td></tr></tbody></table></details> |
|
||||
@@ -74,13 +74,13 @@ Use o parâmetro `tags` com suas *operações de rota* (e `APIRouter`s) para atr
|
||||
|
||||
{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Leia mais sobre tags em [Configuração de operação de rota](path-operation-configuration.md#tags).
|
||||
|
||||
///
|
||||
|
||||
### Cheque os documentos { #check-the-docs }
|
||||
### Verifique a documentação { #check-the-docs }
|
||||
|
||||
Agora, se você verificar a documentação, ela exibirá todos os metadados adicionais:
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ Eles serão adicionados ao esquema OpenAPI e usados pelas interfaces de document
|
||||
|
||||
### Tags com Enums { #tags-with-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.
|
||||
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`.
|
||||
|
||||
@@ -72,13 +72,13 @@ Você pode especificar a descrição da resposta com o parâmetro `response_desc
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Note que `response_description` se refere especificamente à resposta, a `description` se refere à *operação de rota* em geral.
|
||||
Observe que `response_description` se refere especificamente à resposta, a `description` se refere à *operação de rota* em geral.
|
||||
|
||||
///
|
||||
|
||||
/// check | Verifique
|
||||
/// tip | Dica
|
||||
|
||||
OpenAPI especifica que cada *operação de rota* requer uma descrição de resposta.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Primeiro, importe `Path` de `fastapi`, e importe `Annotated`:
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
O FastAPI adicionou suporte a `Annotated` (e passou a recomendá-lo) na versão 0.95.0.
|
||||
|
||||
@@ -131,7 +131,7 @@ E você também pode declarar validações numéricas:
|
||||
* `lt`: menor que (`l`ess `t`han)
|
||||
* `le`: menor que ou igual (`l`ess than or `e`qual)
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
`Query`, `Path` e outras classes que você verá depois são subclasses de uma classe comum `Param`.
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Você pode declarar o tipo de um parâmetro de path na função, usando as anota
|
||||
|
||||
Neste caso, `item_id` é declarado como um `int`.
|
||||
|
||||
/// check | Verifique
|
||||
/// tip | Dica
|
||||
Isso fornecerá suporte do editor dentro da sua função, com verificações de erros, preenchimento automático, etc.
|
||||
///
|
||||
|
||||
@@ -32,7 +32,7 @@ Se você executar este exemplo e abrir seu navegador em [http://127.0.0.1:8000/i
|
||||
{"item_id":3}
|
||||
```
|
||||
|
||||
/// check | Verifique
|
||||
/// tip | Dica
|
||||
Perceba que o valor que sua função recebeu (e retornou) é `3`, como um `int` do Python, não uma string `"3"`.
|
||||
|
||||
Então, com essa declaração de tipo, o **FastAPI** fornece <dfn title="convertendo a string que vem de um request HTTP em dados Python">"parsing"</dfn> automático do request.
|
||||
@@ -62,7 +62,7 @@ porque o parâmetro de path `item_id` tinha o valor `"foo"`, que não é um `int
|
||||
|
||||
O mesmo erro apareceria se você fornecesse um `float` em vez de um `int`, como em: [http://127.0.0.1:8000/items/4.2](http://127.0.0.1:8000/items/4.2)
|
||||
|
||||
/// check | Verifique
|
||||
/// tip | Dica
|
||||
Então, com a mesma declaração de tipo do Python, o **FastAPI** fornece validação de dados.
|
||||
|
||||
Observe que o erro também declara claramente exatamente o ponto onde a validação não passou.
|
||||
@@ -76,7 +76,7 @@ E quando você abrir seu navegador em [http://127.0.0.1:8000/docs](http://127.0.
|
||||
|
||||
<img src="/img/tutorial/path-params/image01.png">
|
||||
|
||||
/// check | Verifique
|
||||
/// tip | Dica
|
||||
Novamente, apenas com a mesma declaração de tipo do Python, o **FastAPI** fornece documentação automática e interativa (integrando o Swagger UI).
|
||||
|
||||
Observe que o parâmetro de path está declarado como um inteiro.
|
||||
|
||||
@@ -18,7 +18,7 @@ Ter `str | None` permitirá que seu editor lhe ofereça melhor suporte e detecte
|
||||
|
||||
## Validação adicional { #additional-validation }
|
||||
|
||||
Vamos impor que, embora `q` seja opcional, sempre que for fornecido, seu comprimento não exceda 50 caracteres.
|
||||
Vamos impor que, embora `q` seja opcional, sempre que for fornecido, **seu comprimento não exceda 50 caracteres**.
|
||||
|
||||
### Importe `Query` e `Annotated` { #import-query-and-annotated }
|
||||
|
||||
@@ -29,7 +29,7 @@ Para isso, primeiro importe:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
O FastAPI adicionou suporte a `Annotated` (e passou a recomendá-lo) na versão 0.95.0.
|
||||
|
||||
@@ -69,19 +69,19 @@ Agora que temos esse `Annotated` onde podemos colocar mais informações (neste
|
||||
|
||||
Perceba que o valor padrão continua sendo `None`, então o parâmetro ainda é opcional.
|
||||
|
||||
Mas agora, com `Query(max_length=50)` dentro de `Annotated`, estamos dizendo ao FastAPI que queremos validação adicional para este valor, queremos que tenha no máximo 50 caracteres. 😎
|
||||
Mas agora, com `Query(max_length=50)` dentro de `Annotated`, estamos dizendo ao FastAPI que queremos **validação adicional** para este valor, queremos que tenha no máximo 50 caracteres. 😎
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Aqui estamos usando `Query()` porque este é um parâmetro de consulta. Mais adiante veremos outros como `Path()`, `Body()`, `Header()` e `Cookie()`, que também aceitam os mesmos argumentos que `Query()`.
|
||||
Aqui estamos usando `Query()` porque este é um **parâmetro de consulta**. Mais adiante veremos outros como `Path()`, `Body()`, `Header()` e `Cookie()`, que também aceitam os mesmos argumentos que `Query()`.
|
||||
|
||||
///
|
||||
|
||||
Agora o FastAPI vai:
|
||||
|
||||
* Validar os dados garantindo que o comprimento máximo seja de 50 caracteres
|
||||
* Mostrar um erro claro para o cliente quando os dados não forem válidos
|
||||
* Documentar o parâmetro na operação de rota do esquema OpenAPI (então ele aparecerá na UI de docs automática)
|
||||
* **Validar** os dados garantindo que o comprimento máximo seja de 50 caracteres
|
||||
* Mostrar um **erro claro** para o cliente quando os dados não forem válidos
|
||||
* **Documentar** o parâmetro na *operação de rota* do esquema OpenAPI (então ele aparecerá na **UI de documentação automática**)
|
||||
|
||||
## Alternativa (antiga): `Query` como valor padrão { #alternative-old-query-as-the-default-value }
|
||||
|
||||
@@ -120,7 +120,7 @@ Então, podemos passar mais parâmetros para `Query`. Neste caso, o parâmetro `
|
||||
q: str | None = Query(default=None, max_length=50)
|
||||
```
|
||||
|
||||
Isso validará os dados, mostrará um erro claro quando os dados não forem válidos e documentará o parâmetro na operação de rota do esquema OpenAPI.
|
||||
Isso validará os dados, mostrará um erro claro quando os dados não forem válidos e documentará o parâmetro na *operação de rota* do esquema OpenAPI.
|
||||
|
||||
### `Query` como valor padrão ou em `Annotated` { #query-as-the-default-value-or-in-annotated }
|
||||
|
||||
@@ -150,13 +150,13 @@ q: str = Query(default="rick")
|
||||
|
||||
### Vantagens de `Annotated` { #advantages-of-annotated }
|
||||
|
||||
Usar `Annotated` é recomendado em vez do valor padrão nos parâmetros da função, é melhor por vários motivos. 🤓
|
||||
**Usar `Annotated` é recomendado** em vez do valor padrão nos parâmetros da função, é **melhor** por vários motivos. 🤓
|
||||
|
||||
O valor padrão do parâmetro da função é o valor padrão real, isso é mais intuitivo com Python em geral. 😌
|
||||
O valor **padrão** do **parâmetro da função** é o valor **padrão real**, isso é mais intuitivo com Python em geral. 😌
|
||||
|
||||
Você poderia chamar essa mesma função em outros lugares sem FastAPI, e ela funcionaria como esperado. Se houver um parâmetro obrigatório (sem valor padrão), seu editor vai avisar com um erro, e o Python também reclamará se você executá-la sem passar o parâmetro obrigatório.
|
||||
Você poderia **chamar** essa mesma função em **outros lugares** sem FastAPI, e ela **funcionaria como esperado**. Se houver um parâmetro **obrigatório** (sem valor padrão), seu **editor** vai avisar com um erro, e o **Python** também reclamará se você executá-la sem passar o parâmetro obrigatório.
|
||||
|
||||
Quando você não usa `Annotated` e em vez disso usa o estilo de valor padrão (antigo), se você chamar essa função sem FastAPI em outros lugares, terá que lembrar de passar os argumentos para a função para que funcione corretamente, caso contrário os valores serão diferentes do esperado (por exemplo, `QueryInfo` ou algo parecido em vez de `str`). E seu editor não vai avisar, e o Python também não vai reclamar ao executar a função, apenas quando as operações internas falharem.
|
||||
Quando você não usa `Annotated` e em vez disso usa o **estilo de valor padrão (antigo)**, se você chamar essa função sem FastAPI em **outros lugares**, terá que **lembrar** de passar os argumentos para a função para que funcione corretamente, caso contrário os valores serão diferentes do esperado (por exemplo, `QueryInfo` ou algo parecido em vez de `str`). E seu editor não vai avisar, e o Python também não vai reclamar ao executar a função, apenas quando as operações internas falharem.
|
||||
|
||||
Como `Annotated` pode ter mais de uma anotação de metadados, você agora pode até usar a mesma função com outras ferramentas, como o [Typer](https://typer.tiangolo.com/). 🚀
|
||||
|
||||
@@ -168,7 +168,7 @@ Você também pode adicionar um parâmetro `min_length`:
|
||||
|
||||
## Adicione expressões regulares { #add-regular-expressions }
|
||||
|
||||
Você pode definir um `pattern` de <dfn title="Uma expressão regular (regex ou regexp) é uma sequência de caracteres que define um padrão de busca para strings.">expressão regular</dfn> que o parâmetro deve corresponder:
|
||||
Você pode definir um `pattern` de <dfn title="Uma expressão regular, regex ou regexp é uma sequência de caracteres que define um padrão de busca para strings.">expressão regular</dfn> que o parâmetro deve corresponder:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
|
||||
|
||||
@@ -178,9 +178,9 @@ Esse padrão específico de expressão regular verifica se o valor recebido no p
|
||||
* `fixedquery`: tem exatamente o valor `fixedquery`.
|
||||
* `$`: termina ali, não tem mais caracteres depois de `fixedquery`.
|
||||
|
||||
Se você se sentir perdido com essas ideias de "expressão regular", não se preocupe. Esse é um assunto difícil para muitas pessoas. Você ainda pode fazer muitas coisas sem precisar de expressões regulares por enquanto.
|
||||
Se você se sentir perdido com essas ideias de **"expressão regular"**, não se preocupe. Esse é um assunto difícil para muitas pessoas. Você ainda pode fazer muitas coisas sem precisar de expressões regulares por enquanto.
|
||||
|
||||
Agora você sabe que, sempre que precisar delas, pode usá-las no FastAPI.
|
||||
Agora você sabe que, sempre que precisar delas, pode usá-las no **FastAPI**.
|
||||
|
||||
## Valores padrão { #default-values }
|
||||
|
||||
@@ -242,7 +242,7 @@ Então, com uma URL como:
|
||||
http://localhost:8000/items/?q=foo&q=bar
|
||||
```
|
||||
|
||||
você receberia os múltiplos valores dos parâmetros de consulta `q` (`foo` e `bar`) em uma `list` Python dentro da sua função de operação de rota, no parâmetro da função `q`.
|
||||
você receberia os múltiplos valores dos *parâmetros de consulta* `q` (`foo` e `bar`) em uma `list` Python dentro da sua *função de operação de rota*, no *parâmetro da função* `q`.
|
||||
|
||||
Assim, a resposta para essa URL seria:
|
||||
|
||||
@@ -298,7 +298,7 @@ Você também pode usar `list` diretamente em vez de `list[str]`:
|
||||
|
||||
Tenha em mente que, neste caso, o FastAPI não verificará o conteúdo da lista.
|
||||
|
||||
Por exemplo, `list[int]` verificaria (and documentaria) que os conteúdos da lista são inteiros. Mas `list` sozinho não.
|
||||
Por exemplo, `list[int]` verificaria (e documentaria) que os conteúdos da lista são inteiros. Mas `list` sozinho não.
|
||||
|
||||
///
|
||||
|
||||
@@ -360,15 +360,15 @@ A documentação vai mostrar assim:
|
||||
|
||||
## Excluir parâmetros do OpenAPI { #exclude-parameters-from-openapi }
|
||||
|
||||
Para excluir um parâmetro de consulta do OpenAPI gerado (e portanto, dos sistemas de documentação automáticos), defina o parâmetro `include_in_schema` de `Query` como `False`:
|
||||
Para excluir um parâmetro de consulta do esquema OpenAPI gerado (e portanto, dos sistemas de documentação automáticos), defina o parâmetro `include_in_schema` de `Query` como `False`:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
|
||||
|
||||
## Validação personalizada { #custom-validation }
|
||||
|
||||
Podem existir casos em que você precise fazer alguma validação personalizada que não pode ser feita com os parâmetros mostrados acima.
|
||||
Podem existir casos em que você precise fazer alguma **validação personalizada** que não pode ser feita com os parâmetros mostrados acima.
|
||||
|
||||
Nesses casos, você pode usar uma função validadora personalizada que é aplicada após a validação normal (por exemplo, depois de validar que o valor é uma `str`).
|
||||
Nesses casos, você pode usar uma **função validadora personalizada** que é aplicada após a validação normal (por exemplo, depois de validar que o valor é uma `str`).
|
||||
|
||||
Você pode fazer isso usando o [`AfterValidator` do Pydantic](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) dentro de `Annotated`.
|
||||
|
||||
@@ -382,7 +382,7 @@ Por exemplo, este validador personalizado verifica se o ID do item começa com `
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Isso está disponível com a versão 2 do Pydantic ou superior. 😎
|
||||
|
||||
@@ -390,15 +390,15 @@ Isso está disponível com a versão 2 do Pydantic ou superior. 😎
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Se você precisar fazer qualquer tipo de validação que exija comunicação com algum componente externo, como um banco de dados ou outra API, você deveria usar Dependências do FastAPI em vez disso; você aprenderá sobre elas mais adiante.
|
||||
Se você precisar fazer qualquer tipo de validação que exija comunicação com algum **componente externo**, como um banco de dados ou outra API, você deveria usar **Dependências do FastAPI** em vez disso; você aprenderá sobre elas mais adiante.
|
||||
|
||||
Esses validadores personalizados são para coisas que podem ser verificadas apenas com os mesmos dados fornecidos na requisição.
|
||||
Esses validadores personalizados são para coisas que podem ser verificadas **apenas** com os **mesmos dados** fornecidos na requisição.
|
||||
|
||||
///
|
||||
|
||||
### Entenda esse código { #understand-that-code }
|
||||
|
||||
O ponto importante é apenas usar `AfterValidator` com uma função dentro de `Annotated`. Sinta-se à vontade para pular esta parte. 🤸
|
||||
O ponto importante é apenas usar **`AfterValidator` com uma função dentro de `Annotated`**. Sinta-se à vontade para pular esta parte. 🤸
|
||||
|
||||
---
|
||||
|
||||
@@ -414,15 +414,15 @@ Percebeu? Uma string usando `value.startswith()` pode receber uma tupla, e verif
|
||||
|
||||
Com `data.items()` obtemos um <dfn title="Algo que podemos iterar com um laço for, como uma list, set, etc.">objeto iterável</dfn> com tuplas contendo a chave e o valor de cada item do dicionário.
|
||||
|
||||
Convertimos esse objeto iterável em uma `list` adequada com `list(data.items())`.
|
||||
Convertemos esse objeto iterável em uma `list` adequada com `list(data.items())`.
|
||||
|
||||
Em seguida, com `random.choice()` podemos obter um valor aleatório da lista, então obtemos uma tupla com `(id, name)`. Será algo como `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
|
||||
Em seguida, com `random.choice()` podemos obter um **valor aleatório** da lista, então obtemos uma tupla com `(id, name)`. Será algo como `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
|
||||
|
||||
Depois atribuímos esses dois valores da tupla às variáveis `id` e `name`.
|
||||
Depois **atribuímos esses dois valores** da tupla às variáveis `id` e `name`.
|
||||
|
||||
Assim, se o usuário não fornecer um ID de item, ele ainda receberá uma sugestão aleatória.
|
||||
|
||||
...fazemos tudo isso em uma única linha simples. 🤯 Você não ama Python? 🐍
|
||||
...fazemos tudo isso em uma **única linha simples**. 🤯 Você não ama Python? 🐍
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
|
||||
|
||||
|
||||
@@ -54,8 +54,8 @@ http://127.0.0.1:8000/items/?skip=20
|
||||
|
||||
Os valores dos parâmetros na sua função serão:
|
||||
|
||||
* `skip=20`: Por que você definiu isso na URL
|
||||
* `limit=10`: Por que esse era o valor padrão
|
||||
* `skip=20`: porque você definiu isso na URL
|
||||
* `limit=10`: porque esse era o valor padrão
|
||||
|
||||
## Parâmetros opcionais { #optional-parameters }
|
||||
|
||||
@@ -65,7 +65,7 @@ Da mesma forma, você pode declarar parâmetros de consulta opcionais, definindo
|
||||
|
||||
Nesse caso, o parâmetro da função `q` será opcional, e `None` será o padrão.
|
||||
|
||||
/// check | Verifique
|
||||
/// tip | Dica
|
||||
|
||||
Você também pode notar que o **FastAPI** é esperto o suficiente para perceber que o parâmetro da rota `item_id` é um parâmetro da rota, e `q` não é, portanto, `q` é o parâmetro de consulta.
|
||||
|
||||
@@ -109,6 +109,7 @@ http://127.0.0.1:8000/items/foo?short=yes
|
||||
|
||||
ou qualquer outra variação (tudo em maiúscula, primeira letra em maiúscula, etc), a sua função vai ver o parâmetro `short` com um valor `bool` de `True`. Caso contrário `False`.
|
||||
|
||||
|
||||
## Múltiplos parâmetros de rota e consulta { #multiple-path-and-query-parameters }
|
||||
|
||||
Você pode declarar múltiplos parâmetros de rota e parâmetros de consulta ao mesmo tempo, o **FastAPI** vai saber o quê é o quê.
|
||||
@@ -129,9 +130,9 @@ Porém, quando você quiser fazer com que o parâmetro de consulta seja obrigat
|
||||
|
||||
{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}
|
||||
|
||||
Aqui o parâmetro da consulta `needy` é um valor obrigatório, do tipo `str`.
|
||||
Aqui o parâmetro da consulta `needy` é um parâmetro de consulta obrigatório, do tipo `str`.
|
||||
|
||||
Se você abrir no seu navegador a URL:
|
||||
Se você abrir no seu navegador uma URL como:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo-item
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Você pode definir arquivos para serem enviados pelo cliente usando `File`.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Para receber arquivos enviados, primeiro instale [`python-multipart`](https://github.com/Kludex/python-multipart).
|
||||
|
||||
@@ -28,7 +28,7 @@ Crie parâmetros de arquivo da mesma forma que você faria para `Body` ou `Form`
|
||||
|
||||
{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
`File` é uma classe que herda diretamente de `Form`.
|
||||
|
||||
@@ -44,7 +44,7 @@ Para declarar corpos de arquivos, você precisa usar `File`, caso contrário, os
|
||||
|
||||
Os arquivos serão enviados como "dados de formulário".
|
||||
|
||||
Se você declarar o tipo do parâmetro da função da sua *operação de rota* como `bytes`, o **FastAPI** lerá o arquivo para você e você receberá o conteúdo como `bytes`.
|
||||
Se você declarar o tipo do parâmetro da sua *função de operação de rota* como `bytes`, o **FastAPI** lerá o arquivo para você e você receberá o conteúdo como `bytes`.
|
||||
|
||||
Mantenha em mente que isso significa que todo o conteúdo será armazenado na memória. Isso funcionará bem para arquivos pequenos.
|
||||
|
||||
@@ -63,8 +63,8 @@ Utilizar `UploadFile` tem várias vantagens sobre `bytes`:
|
||||
* Um arquivo armazenado na memória até um limite máximo de tamanho, e após passar esse limite, ele será armazenado no disco.
|
||||
* Isso significa que funcionará bem para arquivos grandes como imagens, vídeos, binários grandes, etc., sem consumir toda a memória.
|
||||
* Você pode receber metadados do arquivo enviado.
|
||||
* Ele tem uma [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) interface `assíncrona`.
|
||||
* Ele expõe um objeto python [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) que você pode passar diretamente para outras bibliotecas que esperam um objeto semelhante a um arquivo.
|
||||
* Ele tem uma interface [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) `async`.
|
||||
* Ele expõe um objeto Python [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) real que você pode passar diretamente para outras bibliotecas que esperam um objeto semelhante a um arquivo.
|
||||
|
||||
### `UploadFile` { #uploadfile }
|
||||
|
||||
@@ -72,9 +72,9 @@ Utilizar `UploadFile` tem várias vantagens sobre `bytes`:
|
||||
|
||||
* `filename`: Uma `str` com o nome do arquivo original que foi enviado (por exemplo, `myimage.jpg`).
|
||||
* `content_type`: Uma `str` com o tipo de conteúdo (MIME type / media type) (por exemplo, `image/jpeg`).
|
||||
* `file`: Um [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) (um [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) objeto). Este é o objeto de arquivo Python que você pode passar diretamente para outras funções ou bibliotecas que esperam um objeto semelhante a um arquivo.
|
||||
* `file`: Um [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) (um objeto [file-like](https://docs.python.org/3/glossary.html#term-file-like-object)). Este é o objeto de arquivo Python que você pode passar diretamente para outras funções ou bibliotecas que esperam um objeto semelhante a um arquivo.
|
||||
|
||||
`UploadFile` tem os seguintes métodos `assíncronos`. Todos eles chamam os métodos de arquivo correspondentes por baixo dos panos (usando o `SpooledTemporaryFile` interno).
|
||||
`UploadFile` tem os seguintes métodos `async`. Todos eles chamam os métodos de arquivo correspondentes por baixo dos panos (usando o `SpooledTemporaryFile` interno).
|
||||
|
||||
* `write(data)`: Escreve `data` (`str` ou `bytes`) no arquivo.
|
||||
* `read(size)`: Lê `size` (`int`) bytes/caracteres do arquivo.
|
||||
@@ -83,15 +83,15 @@ Utilizar `UploadFile` tem várias vantagens sobre `bytes`:
|
||||
* Isso é especialmente útil se você executar `await myfile.read()` uma vez e precisar ler o conteúdo novamente.
|
||||
* `close()`: Fecha o arquivo.
|
||||
|
||||
Como todos esses métodos são métodos `assíncronos`, você precisa "aguardar" por eles.
|
||||
Como todos esses métodos são métodos `async`, você precisa "aguardar" por eles.
|
||||
|
||||
Por exemplo, dentro de uma função de *operação de rota* `assíncrona`, você pode obter o conteúdo com:
|
||||
Por exemplo, dentro de uma *função de operação de rota* `async`, você pode obter o conteúdo com:
|
||||
|
||||
```Python
|
||||
contents = await myfile.read()
|
||||
```
|
||||
|
||||
Se você estiver dentro de uma função de *operação de rota* normal `def`, você pode acessar o `UploadFile.file` diretamente, por exemplo:
|
||||
Se você estiver dentro de uma *função de operação de rota* normal `def`, você pode acessar o `UploadFile.file` diretamente, por exemplo:
|
||||
|
||||
```Python
|
||||
contents = myfile.file.read()
|
||||
@@ -109,7 +109,7 @@ O `UploadFile` do **FastAPI** herda diretamente do `UploadFile` do **Starlette**
|
||||
|
||||
///
|
||||
|
||||
## O que é "Form Data" { #what-is-form-data }
|
||||
## O que são "Dados de Formulário" { #what-is-form-data }
|
||||
|
||||
O jeito que os formulários HTML (`<form></form>`) enviam os dados para o servidor normalmente usa uma codificação "especial" para esses dados, a qual é diferente do JSON.
|
||||
|
||||
@@ -119,9 +119,9 @@ O jeito que os formulários HTML (`<form></form>`) enviam os dados para o servid
|
||||
|
||||
Dados de formulários normalmente são codificados usando o "media type" `application/x-www-form-urlencoded` quando não incluem arquivos.
|
||||
|
||||
Mas quando o formulário inclui arquivos, ele é codificado como `multipart/form-data`. Se você usar `File`, o **FastAPI** saberá que tem que pegar os arquivos da parte correta do corpo da requisição.
|
||||
Mas quando o formulário inclui arquivos, ele é codificado como `multipart/form-data`. Se você usar `File`, o **FastAPI** saberá que tem que pegar os arquivos da parte correta do corpo.
|
||||
|
||||
Se você quiser ler mais sobre essas codificações e campos de formulário, vá para a [<abbr title="Mozilla Developer Network - Rede de Desenvolvedores da Mozilla">MDN</abbr> web docs para `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).
|
||||
Se você quiser ler mais sobre essas codificações e campos de formulário, vá para a [documentação web da <abbr title="Mozilla Developer Network - Rede de Desenvolvedores da Mozilla">MDN</abbr> para `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Você pode utilizar **Modelos Pydantic** para declarar **campos de formulários** no FastAPI.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Para utilizar formulários, instale primeiramente o [`python-multipart`](https://github.com/Kludex/python-multipart).
|
||||
|
||||
@@ -28,7 +28,7 @@ Você precisa apenas declarar um **modelo Pydantic** com os campos que deseja re
|
||||
|
||||
O **FastAPI** irá **extrair** as informações para **cada campo** dos **dados do formulário** na requisição e dar para você o modelo Pydantic que você definiu.
|
||||
|
||||
## Confira os Documentos { #check-the-docs }
|
||||
## Confira a Documentação { #check-the-docs }
|
||||
|
||||
Você pode verificar na UI de documentação em `/docs`:
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Você pode definir arquivos e campos de formulário ao mesmo tempo usando `File` e `Form`.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Para receber arquivos carregados e/ou dados de formulário, primeiro instale [`python-multipart`](https://github.com/Kludex/python-multipart).
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Quando você precisar receber campos de formulário em vez de JSON, você pode usar `Form`.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Para usar formulários, primeiro instale [`python-multipart`](https://github.com/Kludex/python-multipart).
|
||||
|
||||
@@ -32,7 +32,7 @@ A <dfn title="especificação">especificação</dfn> exige que os campos sejam e
|
||||
|
||||
Com `Form` você pode declarar as mesmas configurações que com `Body` (e `Query`, `Path`, `Cookie`), incluindo validação, exemplos, um alias (por exemplo, `user-name` em vez de `username`), etc.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
`Form` é uma classe que herda diretamente de `Body`.
|
||||
|
||||
@@ -56,7 +56,7 @@ Os dados dos formulários são normalmente codificados usando o "media type" `ap
|
||||
|
||||
Mas quando o formulário inclui arquivos, ele é codificado como `multipart/form-data`. Você lerá sobre como lidar com arquivos no próximo capítulo.
|
||||
|
||||
Se você quiser ler mais sobre essas codificações e campos de formulário, vá para o [<abbr title="Mozilla Developer Network - Rede de Desenvolvedores da Mozilla">MDN</abbr> web docs para `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).
|
||||
Se você quiser ler mais sobre essas codificações e campos de formulário, vá para a [documentação web da <abbr title="Mozilla Developer Network - Rede de Desenvolvedores da Mozilla">MDN</abbr> para `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ Aqui estamos declarando um modelo `UserIn`, ele conterá uma senha em texto simp
|
||||
|
||||
{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Para usar `EmailStr`, primeiro instale [`email-validator`](https://github.com/JoshData/python-email-validator).
|
||||
|
||||
@@ -251,7 +251,7 @@ Então, se você enviar uma solicitação para essa *operação de rota* para o
|
||||
}
|
||||
```
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Você também pode usar:
|
||||
|
||||
|
||||
@@ -12,13 +12,13 @@ Da mesma forma que você pode especificar um modelo de resposta, você também p
|
||||
|
||||
/// note | Nota
|
||||
|
||||
Observe que `status_code` é um parâmetro do método "decorador" (`get`, `post`, etc). Não da sua função de *operação de rota*, como todos os parâmetros e corpo.
|
||||
Observe que `status_code` é um parâmetro do método "decorador" (`get`, `post`, etc). Não da sua *função de operação de rota*, como todos os parâmetros e corpo.
|
||||
|
||||
///
|
||||
|
||||
O parâmetro `status_code` recebe um número com o código de status HTTP.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
`status_code` também pode receber um `IntEnum`, como [`http.HTTPStatus`](https://docs.python.org/3/library/http.html#http.HTTPStatus) do Python.
|
||||
|
||||
@@ -35,7 +35,7 @@ Dessa forma:
|
||||
|
||||
Alguns códigos de resposta (consulte a próxima seção) indicam que a resposta não possui um corpo.
|
||||
|
||||
O FastAPI sabe disso e produzirá documentos OpenAPI informando que não há corpo de resposta.
|
||||
O FastAPI sabe disso e produzirá documentação OpenAPI informando que não há corpo de resposta.
|
||||
|
||||
///
|
||||
|
||||
@@ -84,7 +84,7 @@ Você pode usar as variáveis de conveniência de `fastapi.status`.
|
||||
|
||||
{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}
|
||||
|
||||
Eles são apenas uma conveniência, eles possuem o mesmo número, mas dessa forma você pode usar o preenchimento automático do editor para encontrá-los:
|
||||
Eles são apenas uma conveniência, eles possuem o mesmo número, mas dessa forma você pode usar o autocompletar do editor para encontrá-los:
|
||||
|
||||
<img src="/img/tutorial/response-status-code/image02.png">
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Declare dados de exemplo da requisição { #declare-request-example-data }
|
||||
|
||||
|
||||
Você pode declarar exemplos dos dados que sua aplicação pode receber.
|
||||
|
||||
Aqui estão várias maneiras de fazer isso.
|
||||
@@ -24,7 +25,7 @@ Por exemplo, você poderia usá-la para adicionar metadados para uma interface d
|
||||
|
||||
///
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
O OpenAPI 3.1.0 (usado desde o FastAPI 0.99.0) adicionou suporte a `examples`, que faz parte do padrão **JSON Schema**.
|
||||
|
||||
@@ -155,7 +156,7 @@ O OpenAPI também adicionou os campos `example` e `examples` a outras partes da
|
||||
* `File()`
|
||||
* `Form()`
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Esse parâmetro antigo `examples` específico do OpenAPI agora é `openapi_examples` desde o FastAPI `0.103.0`.
|
||||
|
||||
@@ -171,7 +172,7 @@ E agora esse novo campo `examples` tem precedência sobre o antigo campo único
|
||||
|
||||
Esse novo campo `examples` no JSON Schema é **apenas uma `list`** de exemplos, não um dict com metadados extras como nos outros lugares do OpenAPI (descritos acima).
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Mesmo após o lançamento do OpenAPI 3.1.0 com essa nova integração mais simples com o JSON Schema, por um tempo o Swagger UI, a ferramenta que fornece a documentação automática, não suportava OpenAPI 3.1.0 (passou a suportar desde a versão 5.0.0 🎉).
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ Copie o exemplo em um arquivo `main.py`:
|
||||
|
||||
## Execute-o { #run-it }
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
O pacote [`python-multipart`](https://github.com/Kludex/python-multipart) é instalado automaticamente com o **FastAPI** quando você executa o comando `pip install "fastapi[standard]"`.
|
||||
|
||||
@@ -60,11 +60,11 @@ Você verá algo deste tipo:
|
||||
|
||||
<img src="/img/tutorial/security/image01.png">
|
||||
|
||||
/// check | Botão Autorizar!
|
||||
/// tip | Botão Autorizar!
|
||||
|
||||
Você já tem um novo botão 'Authorize'.
|
||||
Você já tem um novo e brilhante botão "Authorize".
|
||||
|
||||
E sua operação de rota tem um pequeno cadeado no canto superior direito em que você pode clicar.
|
||||
E sua *operação de rota* tem um pequeno cadeado no canto superior direito em que você pode clicar.
|
||||
|
||||
///
|
||||
|
||||
@@ -80,7 +80,7 @@ Não importa o que você digite no formulário, ainda não vai funcionar. Mas n
|
||||
|
||||
Claro que este não é o frontend para os usuários finais, mas é uma ótima ferramenta automática para documentar interativamente toda a sua API.
|
||||
|
||||
Pode ser usada pelo time de frontend (que pode ser você mesmo).
|
||||
Pode ser usada pela equipe de frontend (que pode ser você mesmo).
|
||||
|
||||
Pode ser usada por aplicações e sistemas de terceiros.
|
||||
|
||||
@@ -106,7 +106,7 @@ Então, vamos rever de um ponto de vista simplificado:
|
||||
* Então, o usuário terá que fazer login novamente em algum momento.
|
||||
* E se o token for roubado, o risco é menor. Não é como uma chave permanente que funcionará para sempre (na maioria dos casos).
|
||||
* O frontend armazena esse token temporariamente em algum lugar.
|
||||
* O usuário clica no frontend para ir para outra seção do aplicativo web.
|
||||
* O usuário clica no frontend para ir para outra seção da aplicação web do frontend.
|
||||
* O frontend precisa buscar mais dados da API.
|
||||
* Mas precisa de autenticação para aquele endpoint específico.
|
||||
* Então, para autenticar com nossa API, ele envia um header `Authorization` com o valor `Bearer ` mais o token.
|
||||
@@ -118,7 +118,7 @@ O **FastAPI** fornece várias ferramentas, em diferentes níveis de abstração,
|
||||
|
||||
Neste exemplo, vamos usar **OAuth2**, com o fluxo **Password**, usando um token **Bearer**. Fazemos isso usando a classe `OAuth2PasswordBearer`.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Um token "bearer" não é a única opção.
|
||||
|
||||
@@ -144,11 +144,11 @@ Usar uma URL relativa é importante para garantir que sua aplicação continue f
|
||||
|
||||
///
|
||||
|
||||
Esse parâmetro não cria aquele endpoint/operação de rota, mas declara que a URL `/token` será aquela que o client deve usar para obter o token. Essa informação é usada no OpenAPI e depois nos sistemas de documentação interativa da API.
|
||||
Esse parâmetro não cria aquele endpoint / *operação de rota*, mas declara que a URL `/token` será aquela que o client deve usar para obter o token. Essa informação é usada no OpenAPI e depois nos sistemas de documentação interativa da API.
|
||||
|
||||
Em breve também criaremos a operação de rota real.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Se você é um "Pythonista" muito rigoroso, pode não gostar do estilo do nome do parâmetro `tokenUrl` em vez de `token_url`.
|
||||
|
||||
@@ -176,7 +176,7 @@ Essa dependência fornecerá uma `str` que é atribuída ao parâmetro `token` d
|
||||
|
||||
O **FastAPI** saberá que pode usar essa dependência para definir um "esquema de segurança" no esquema OpenAPI (e na documentação automática da API).
|
||||
|
||||
/// info | Detalhes Técnicos
|
||||
/// note | Detalhes Técnicos
|
||||
|
||||
O **FastAPI** saberá que pode usar a classe `OAuth2PasswordBearer` (declarada em uma dependência) para definir o esquema de segurança no OpenAPI porque ela herda de `fastapi.security.oauth2.OAuth2`, que por sua vez herda de `fastapi.security.base.SecurityBase`.
|
||||
|
||||
|
||||
@@ -14,11 +14,11 @@ Primeiro, vamos criar um modelo de usuário com Pydantic.
|
||||
|
||||
Da mesma forma que usamos o Pydantic para declarar corpos, podemos usá-lo em qualquer outro lugar:
|
||||
|
||||
{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}
|
||||
{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:16] *}
|
||||
|
||||
## Criar uma dependência `get_current_user` { #create-a-get-current-user-dependency }
|
||||
|
||||
Vamos criar uma dependência chamada `get_current_user`.
|
||||
Vamos criar uma dependência `get_current_user`.
|
||||
|
||||
Lembra que as dependências podem ter subdependências?
|
||||
|
||||
@@ -52,7 +52,7 @@ Aqui, o **FastAPI** não ficará confuso porque você está usando `Depends`.
|
||||
|
||||
///
|
||||
|
||||
/// check | Verifique
|
||||
/// tip | Dica
|
||||
|
||||
A forma como esse sistema de dependências foi projetado nos permite ter diferentes dependências (diferentes "dependables") que retornam um modelo `User`.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# OAuth2 com Senha (e hashing), Bearer com tokens JWT { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }
|
||||
|
||||
Agora que temos todo o fluxo de segurança, vamos tornar a aplicação realmente segura, usando tokens <abbr title="JSON Web Tokens">JWT</abbr> e hashing de senhas seguras.
|
||||
Agora que temos todo o fluxo de segurança, vamos tornar a aplicação realmente segura, usando tokens <abbr title="JSON Web Tokens">JWT</abbr> e hashing seguro de senhas.
|
||||
|
||||
Este código é algo que você pode realmente usar na sua aplicação, salvar os hashes das senhas no seu banco de dados, etc.
|
||||
|
||||
@@ -42,9 +42,9 @@ $ pip install pyjwt
|
||||
|
||||
</div>
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Se você pretente utilizar algoritmos de assinatura digital como o RSA ou o ECDSA, você deve instalar a dependência da biblioteca de criptografia `pyjwt[crypto]`.
|
||||
Se você pretende utilizar algoritmos de assinatura digital como o RSA ou o ECDSA, você deveria instalar a dependência da biblioteca de criptografia `pyjwt[crypto]`.
|
||||
|
||||
Você pode ler mais sobre isso na [documentação de instalação do PyJWT](https://pyjwt.readthedocs.io/en/latest/installation.html).
|
||||
|
||||
@@ -88,7 +88,7 @@ $ pip install "pwdlib[argon2]"
|
||||
|
||||
Com o `pwdlib`, você poderia até configurá-lo para ser capaz de ler senhas criadas pelo **Django**, um plug-in de segurança do **Flask** ou muitos outros.
|
||||
|
||||
Assim, você poderia, por exemplo, compartilhar os mesmos dados de um aplicativo Django em um banco de dados com um aplicativo FastAPI. Ou migrar gradualmente uma aplicação Django usando o mesmo banco de dados.
|
||||
Assim, você poderia, por exemplo, compartilhar os mesmos dados de uma aplicação Django em um banco de dados com uma aplicação FastAPI. Ou migrar gradualmente uma aplicação Django usando o mesmo banco de dados.
|
||||
|
||||
E seus usuários poderiam fazer login tanto pela sua aplicação Django quanto pela sua aplicação **FastAPI**, ao mesmo tempo.
|
||||
|
||||
@@ -213,7 +213,7 @@ Usando as credenciais:
|
||||
Username: `johndoe`
|
||||
Password: `secret`
|
||||
|
||||
/// check | Verifique
|
||||
/// tip | Dica
|
||||
|
||||
Observe que em nenhuma parte do código está a senha em texto puro "`secret`", nós temos apenas o hash.
|
||||
|
||||
@@ -260,7 +260,7 @@ Com o que você viu até agora, você pode configurar uma aplicação **FastAPI*
|
||||
|
||||
Em quase qualquer framework, lidar com a segurança se torna rapidamente um assunto bastante complexo.
|
||||
|
||||
Muitos pacotes que simplificam bastante isso precisam fazer muitas concessões com o modelo de dados, o banco de dados e os recursos disponíveis. E alguns desses pacotes que simplificam demais na verdade têm falhas de segurança subjacentes.
|
||||
Muitos pacotes que simplificam bastante isso precisam fazer muitas concessões com o modelo de dados, o banco de dados e as funcionalidades disponíveis. E alguns desses pacotes que simplificam demais na verdade têm falhas de segurança subjacentes.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ Agora vamos construir a partir do capítulo anterior e adicionar as partes que f
|
||||
|
||||
## Obtenha o `username` e a `password` { #get-the-username-and-password }
|
||||
|
||||
É utilizado o utils de segurança da **FastAPI** para obter o `username` e a `password`.
|
||||
Vamos usar os utilitários de segurança da **FastAPI** para obter o `username` e a `password`.
|
||||
|
||||
OAuth2 especifica que ao usar o "password flow" (fluxo de senha), que estamos usando, o cliente/usuário deve enviar os campos `username` e `password` como dados do formulário.
|
||||
OAuth2 especifica que, ao usar o "fluxo de senha" (que estamos usando), o cliente/usuário deve enviar os campos `username` e `password` como dados do formulário.
|
||||
|
||||
E a especificação diz que os campos devem ser nomeados assim. Portanto, `user-name` ou `email` não funcionariam.
|
||||
|
||||
@@ -29,10 +29,10 @@ Cada “scope” é apenas uma string (sem espaços).
|
||||
Normalmente são usados para declarar permissões de segurança específicas, por exemplo:
|
||||
|
||||
* `users:read` ou `users:write` são exemplos comuns.
|
||||
* `instagram_basic` é usado pelo Facebook e Instagram.
|
||||
* `instagram_basic` é usado pelo Facebook / Instagram.
|
||||
* `https://www.googleapis.com/auth/drive` é usado pelo Google.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
No OAuth2, um "scope" é apenas uma string que declara uma permissão específica necessária.
|
||||
|
||||
@@ -72,13 +72,13 @@ Se você precisar aplicá-lo, use `OAuth2PasswordRequestFormStrict` em vez de `O
|
||||
* Um `client_id` opcional (não precisamos dele em nosso exemplo).
|
||||
* Um `client_secret` opcional (não precisamos dele em nosso exemplo).
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
O `OAuth2PasswordRequestForm` não é uma classe especial para **FastAPI** como é `OAuth2PasswordBearer`.
|
||||
|
||||
`OAuth2PasswordBearer` faz com que **FastAPI** saiba que é um esquema de segurança. Portanto, é adicionado dessa forma ao OpenAPI.
|
||||
|
||||
Mas `OAuth2PasswordRequestForm` é apenas uma dependência de classe que você mesmo poderia ter escrito ou poderia ter declarado os parâmetros do `Form` (formulário) diretamente.
|
||||
Mas `OAuth2PasswordRequestForm` é apenas uma dependência de classe que você mesmo poderia ter escrito ou poderia ter declarado os parâmetros de `Form` diretamente.
|
||||
|
||||
Mas como é um caso de uso comum, ele é fornecido diretamente pelo **FastAPI**, apenas para facilitar.
|
||||
|
||||
@@ -108,7 +108,7 @@ Neste ponto temos os dados do usuário do nosso banco de dados, mas não verific
|
||||
|
||||
Vamos colocar esses dados primeiro no modelo `UserInDB` do Pydantic.
|
||||
|
||||
Você nunca deve salvar senhas em texto simples, portanto, usaremos o sistema de hashing de senhas (falsas).
|
||||
Você nunca deveria salvar senhas em texto simples, portanto, usaremos o sistema (falso) de hashing de senhas.
|
||||
|
||||
Se as senhas não corresponderem, retornaremos o mesmo erro.
|
||||
|
||||
@@ -120,7 +120,7 @@ Sempre que você passa exatamente o mesmo conteúdo (exatamente a mesma senha),
|
||||
|
||||
Mas você não pode converter a sequência aleatória de caracteres de volta para a senha.
|
||||
|
||||
##### Porque usar hashing de senha { #why-use-password-hashing }
|
||||
##### Por que usar hashing de senha { #why-use-password-hashing }
|
||||
|
||||
Se o seu banco de dados for roubado, o ladrão não terá as senhas em texto simples dos seus usuários, apenas os hashes.
|
||||
|
||||
@@ -144,10 +144,9 @@ UserInDB(
|
||||
)
|
||||
```
|
||||
|
||||
/// note | Nota
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Para uma explicação mais completa de `**user_dict`, verifique [a documentação para **Extra Models**](../extra-models.md#about-user-in-dict).
|
||||
Para uma explicação mais completa de `**user_dict`, verifique [a documentação para **Extra Models**](../extra-models.md#about-user-in-model-dump).
|
||||
|
||||
///
|
||||
|
||||
@@ -173,7 +172,7 @@ Mas, por enquanto, vamos nos concentrar nos detalhes específicos de que precisa
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Pela especificação, você deve retornar um JSON com um `access_token` e um `token_type`, o mesmo que neste exemplo.
|
||||
Pela especificação, você deveria retornar um JSON com um `access_token` e um `token_type`, o mesmo que neste exemplo.
|
||||
|
||||
Isso é algo que você mesmo deve fazer em seu código e certifique-se de usar essas chaves JSON.
|
||||
|
||||
@@ -197,7 +196,7 @@ Portanto, em nosso endpoint, só obteremos um usuário se o usuário existir, ti
|
||||
|
||||
{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
O cabeçalho adicional `WWW-Authenticate` com valor `Bearer` que estamos retornando aqui também faz parte da especificação.
|
||||
|
||||
@@ -217,7 +216,7 @@ Esse é o benefício dos padrões...
|
||||
|
||||
## Veja em ação { #see-it-in-action }
|
||||
|
||||
Abra o docs interativo: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
|
||||
Abra a documentação interativa: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
|
||||
|
||||
### Autentique-se { #authenticate }
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Você pode transmitir dados para o cliente usando Server-Sent Events (SSE).
|
||||
|
||||
Isso é semelhante a [Stream de JSON Lines](stream-json-lines.md), mas usa o formato `text/event-stream`, que é suportado nativamente pelos navegadores com a [`EventSource` API](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Adicionado no FastAPI 0.135.0.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
Aqui veremos um exemplo usando [SQLModel](https://sqlmodel.tiangolo.com/).
|
||||
|
||||
**SQLModel** é construído sobre [SQLAlchemy](https://www.sqlalchemy.org/) e Pydantic. Ele foi criado pelo mesmo autor do **FastAPI** para ser o par perfeito para aplicações **FastAPI** que precisam usar **bancos de dados SQL**.
|
||||
**SQLModel** é construído sobre [SQLAlchemy](https://www.sqlalchemy.org/) e Pydantic. Ele foi criado pelo mesmo autor do **FastAPI** para ser o par perfeito para aplicações FastAPI que precisam usar **bancos de dados SQL**.
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
@@ -32,7 +32,7 @@ Existe um gerador de projetos oficial com **FastAPI** e **PostgreSQL** incluindo
|
||||
|
||||
Este é um tutorial muito simples e curto, se você quiser aprender sobre bancos de dados em geral, sobre SQL ou recursos mais avançados, acesse a [documentação do SQLModel](https://sqlmodel.tiangolo.com/).
|
||||
|
||||
## Instalar o `SQLModel` { #install-sqlmodel }
|
||||
## Instale o `SQLModel` { #install-sqlmodel }
|
||||
|
||||
Primeiro, certifique-se de criar seu [ambiente virtual](../virtual-environments.md), ativá-lo e, em seguida, instalar o `sqlmodel`:
|
||||
|
||||
@@ -45,13 +45,13 @@ $ pip install sqlmodel
|
||||
|
||||
</div>
|
||||
|
||||
## Crear o App com um Único Modelo { #create-the-app-with-a-single-model }
|
||||
## Crie o App com um Único Modelo { #create-the-app-with-a-single-model }
|
||||
|
||||
Vamos criar a primeira versão mais simples do app com um único modelo **SQLModel**.
|
||||
|
||||
Depois, vamos melhorá-lo aumentando a segurança e versatilidade com **múltiplos modelos** abaixo. 🤓
|
||||
|
||||
### Criar Modelos { #create-models }
|
||||
### Crie Modelos { #create-models }
|
||||
|
||||
Importe o `SQLModel` e crie um modelo de banco de dados:
|
||||
|
||||
@@ -71,7 +71,8 @@ Existem algumas diferenças:
|
||||
|
||||
O SQLModel saberá que algo declarado como `str` será uma coluna SQL do tipo `TEXT` (ou `VARCHAR`, dependendo do banco de dados).
|
||||
|
||||
### Criar um Engine { #create-an-engine }
|
||||
### Crie um Engine { #create-an-engine }
|
||||
|
||||
Um `engine` SQLModel (por baixo dos panos, ele é na verdade um `engine` do SQLAlchemy) é o que **mantém as conexões** com o banco de dados.
|
||||
|
||||
Você teria **um único objeto `engine`** para todo o seu código se conectar ao mesmo banco de dados.
|
||||
@@ -82,13 +83,13 @@ Usar `check_same_thread=False` permite que o FastAPI use o mesmo banco de dados
|
||||
|
||||
Não se preocupe, com a forma como o código está estruturado, garantiremos que usamos **uma única *sessão* SQLModel por requisição** mais tarde, isso é realmente o que o `check_same_thread` está tentando conseguir.
|
||||
|
||||
### Criar as Tabelas { #create-the-tables }
|
||||
### Crie as Tabelas { #create-the-tables }
|
||||
|
||||
Em seguida, adicionamos uma função que usa `SQLModel.metadata.create_all(engine)` para **criar as tabelas** para todos os *modelos de tabela*.
|
||||
|
||||
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}
|
||||
|
||||
### Criar uma Dependência de Sessão { #create-a-session-dependency }
|
||||
### Crie uma Dependência de Sessão { #create-a-session-dependency }
|
||||
|
||||
Uma **`Session`** é o que armazena os **objetos na memória** e acompanha as alterações necessárias nos dados, para então **usar o `engine`** para se comunicar com o banco de dados.
|
||||
|
||||
@@ -98,7 +99,7 @@ Então, criamos uma dependência `Annotated` chamada `SessionDep` para simplific
|
||||
|
||||
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30] hl[25:27,30] *}
|
||||
|
||||
### Criar Tabelas de Banco de Dados na Inicialização { #create-database-tables-on-startup }
|
||||
### Crie Tabelas de Banco de Dados na Inicialização { #create-database-tables-on-startup }
|
||||
|
||||
Vamos criar as tabelas do banco de dados quando o aplicativo for iniciado.
|
||||
|
||||
@@ -114,7 +115,7 @@ O SQLModel terá utilitários de migração envolvendo o Alembic, mas por enquan
|
||||
|
||||
///
|
||||
|
||||
### Criar um Hero { #create-a-hero }
|
||||
### Crie um Hero { #create-a-hero }
|
||||
|
||||
Como cada modelo SQLModel também é um modelo Pydantic, você pode usá-lo nas mesmas **anotações de tipo** que usaria para modelos Pydantic.
|
||||
|
||||
@@ -126,25 +127,25 @@ Da mesma forma, você pode declará-lo como o **tipo de retorno** da função, e
|
||||
|
||||
Aqui, usamos a dependência `SessionDep` (uma `Session`) para adicionar o novo `Hero` à instância `Session`, fazer commit das alterações no banco de dados, atualizar os dados no `hero` e então retorná-lo.
|
||||
|
||||
### Ler Heroes { #read-heroes }
|
||||
### Leia Heroes { #read-heroes }
|
||||
|
||||
Podemos **ler** `Hero`s do banco de dados usando um `select()`. Podemos incluir um `limit` e `offset` para paginar os resultados.
|
||||
|
||||
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}
|
||||
|
||||
### Ler um Único Hero { #read-one-hero }
|
||||
### Leia um Único Hero { #read-one-hero }
|
||||
|
||||
Podemos **ler** um único `Hero`.
|
||||
|
||||
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}
|
||||
|
||||
### Deletar um Hero { #delete-a-hero }
|
||||
### Delete um Hero { #delete-a-hero }
|
||||
|
||||
Também podemos **deletar** um `Hero`.
|
||||
|
||||
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}
|
||||
|
||||
### Executar o App { #run-the-app }
|
||||
### Execute o App { #run-the-app }
|
||||
|
||||
Você pode executar o app:
|
||||
|
||||
@@ -164,19 +165,19 @@ Então, vá para a interface `/docs`, você verá que o **FastAPI** está usando
|
||||
<img src="/img/tutorial/sql-databases/image01.png">
|
||||
</div>
|
||||
|
||||
## Atualizar o App com Múltiplos Modelos { #update-the-app-with-multiple-models }
|
||||
## Atualize o App com Múltiplos Modelos { #update-the-app-with-multiple-models }
|
||||
|
||||
Agora vamos **refatorar** este app um pouco para aumentar a **segurança** e **versatilidade**.
|
||||
|
||||
Se você verificar o app anterior, na interface você pode ser que, até agora, ele permite que o cliente decida o `id` do `Hero` a ser criado. 😱
|
||||
Se você verificar o app anterior, na interface você pode ver que, até agora, ele permite que o cliente decida o `id` do `Hero` a ser criado. 😱
|
||||
|
||||
Não deveríamos deixar isso acontecer, eles poderiam sobrescrever um `id` que já atribuimos na base de dados. Decidir o `id` deve ser feito pelo **backend** ou pelo **banco de dados**, **não pelo cliente**.
|
||||
Não deveríamos deixar isso acontecer, eles poderiam sobrescrever um `id` que já atribuímos no banco de dados. Decidir o `id` deve ser feito pelo **backend** ou pelo **banco de dados**, **não pelo cliente**.
|
||||
|
||||
Além disso, criamos um `secret_name` para o hero, mas até agora estamos retornando ele em todos os lugares, isso não é muito **secreto**... 😅
|
||||
|
||||
Vamos corrigir essas coisas adicionando alguns **modelos extras**. Aqui é onde o SQLModel vai brilhar. ✨
|
||||
|
||||
### Criar Múltiplos Modelos { #create-multiple-models }
|
||||
### Crie Múltiplos Modelos { #create-multiple-models }
|
||||
|
||||
No **SQLModel**, qualquer classe de modelo que tenha `table=True` é um **modelo de tabela**.
|
||||
|
||||
@@ -277,7 +278,7 @@ Os campos de `HeroUpdate` são:
|
||||
|
||||
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}
|
||||
|
||||
### Criar com `HeroCreate` e retornar um `HeroPublic` { #create-with-herocreate-and-return-a-heropublic }
|
||||
### Crie com `HeroCreate` e retorne um `HeroPublic` { #create-with-herocreate-and-return-a-heropublic }
|
||||
|
||||
Agora que temos **múltiplos modelos**, podemos atualizar as partes do app que os utilizam.
|
||||
|
||||
@@ -299,19 +300,19 @@ Ao declará-lo no `response_model`, estamos dizendo ao **FastAPI** para fazer o
|
||||
|
||||
///
|
||||
|
||||
### Ler Heroes com `HeroPublic` { #read-heroes-with-heropublic }
|
||||
### Leia Heroes com `HeroPublic` { #read-heroes-with-heropublic }
|
||||
|
||||
Podemos fazer o mesmo que antes para **ler** `Hero`s, novamente, usamos `response_model=list[HeroPublic]` para garantir que os dados sejam validados e serializados corretamente.
|
||||
|
||||
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}
|
||||
|
||||
### Ler Um Hero com `HeroPublic` { #read-one-hero-with-heropublic }
|
||||
### Leia Um Hero com `HeroPublic` { #read-one-hero-with-heropublic }
|
||||
|
||||
Podemos **ler** um único herói:
|
||||
|
||||
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}
|
||||
|
||||
### Atualizar um Hero com `HeroUpdate` { #update-a-hero-with-heroupdate }
|
||||
### Atualize um Hero com `HeroUpdate` { #update-a-hero-with-heroupdate }
|
||||
|
||||
Podemos **atualizar um hero**. Para isso, usamos uma operação HTTP `PATCH`.
|
||||
|
||||
@@ -321,7 +322,7 @@ Em seguida, usamos `hero_db.sqlmodel_update(hero_data)` para atualizar o `hero_d
|
||||
|
||||
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}
|
||||
|
||||
### Deletar um Hero Novamente { #delete-a-hero-again }
|
||||
### Delete um Hero Novamente { #delete-a-hero-again }
|
||||
|
||||
**Deletar** um hero permanece praticamente o mesmo.
|
||||
|
||||
@@ -329,7 +330,7 @@ Não vamos satisfazer o desejo de refatorar tudo neste aqui. 😅
|
||||
|
||||
{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}
|
||||
|
||||
### Executar o App Novamente { #run-the-app-again }
|
||||
### Execute o App Novamente { #run-the-app-again }
|
||||
|
||||
Você pode executar o app novamente:
|
||||
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
|
||||
Você pode servir arquivos estáticos automaticamente a partir de um diretório usando `StaticFiles`.
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Se você precisar hospedar um frontend, use `app.frontend()` em vez disso, leia sobre isso em [Frontend](frontend.md).
|
||||
|
||||
`app.frontend()` usa `StaticFiles` por baixo, com várias vantagens adicionais para frontends, como lidar com roteamento do lado do cliente.
|
||||
|
||||
///
|
||||
|
||||
## Use `StaticFiles` { #use-staticfiles }
|
||||
|
||||
* Importe `StaticFiles`.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Você pode ter uma sequência de dados que deseja enviar em um "**Stream**"; é possível fazer isso com **JSON Lines**.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Adicionado no FastAPI 0.134.0.
|
||||
|
||||
@@ -48,7 +48,7 @@ Uma response teria um tipo de conteúdo `application/jsonl` (em vez de `applicat
|
||||
|
||||
É muito semelhante a um array JSON (equivalente a uma list do Python), mas em vez de estar envolto em `[]` e ter `,` entre os itens, há **um objeto JSON por linha**, separados por um caractere de nova linha.
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
O ponto importante é que sua aplicação poderá produzir cada linha em sequência, enquanto o cliente consome as anteriores.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Com ele, você pode usar o [pytest](https://docs.pytest.org/) diretamente com **
|
||||
|
||||
## Usando `TestClient` { #using-testclient }
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Para usar o `TestClient`, primeiro instale [`httpx`](https://www.python-httpx.org).
|
||||
|
||||
@@ -52,7 +52,7 @@ Você também pode usar `from starlette.testclient import TestClient`.
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Se você quiser chamar funções `async` em seus testes além de enviar solicitações à sua aplicação FastAPI (por exemplo, funções de banco de dados assíncronas), dê uma olhada em [Testes assíncronos](../advanced/async-tests.md) no tutorial avançado.
|
||||
Se você quiser chamar funções `async` em seus testes além de enviar requests à sua aplicação FastAPI (por exemplo, funções de banco de dados assíncronas), dê uma olhada em [Testes assíncronos](../advanced/async-tests.md) no tutorial avançado.
|
||||
|
||||
///
|
||||
|
||||
@@ -94,6 +94,7 @@ Como esse arquivo está no mesmo pacote, você pode usar importações relativas
|
||||
|
||||
{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}
|
||||
|
||||
|
||||
...e ter o código para os testes como antes.
|
||||
|
||||
## Testando: exemplo estendido { #testing-extended-example }
|
||||
@@ -112,13 +113,13 @@ Vamos continuar com a mesma estrutura de arquivo de antes:
|
||||
│ └── test_main.py
|
||||
```
|
||||
|
||||
Digamos que agora o arquivo `main.py` com sua aplicação **FastAPI** tenha algumas outras **operações de rotas**.
|
||||
Digamos que agora o arquivo `main.py` com sua aplicação **FastAPI** tenha algumas outras **operações de rota**.
|
||||
|
||||
Ele tem uma operação `GET` que pode retornar um erro.
|
||||
|
||||
Ele tem uma operação `POST` que pode retornar vários erros.
|
||||
|
||||
Ambas as *operações de rotas* requerem um cabeçalho `X-Token`.
|
||||
Ambas as *operações de rota* requerem um cabeçalho `X-Token`.
|
||||
|
||||
{* ../../docs_src/app_testing/app_b_an_py310/main.py *}
|
||||
|
||||
@@ -128,6 +129,7 @@ Você pode então atualizar `test_main.py` com os testes estendidos:
|
||||
|
||||
{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}
|
||||
|
||||
|
||||
Sempre que você precisar que o cliente passe informações na requisição e não souber como, você pode pesquisar (no Google) como fazer isso no `httpx`, ou até mesmo como fazer isso com `requests`, já que o design do HTTPX é baseado no design do Requests.
|
||||
|
||||
Depois é só fazer o mesmo nos seus testes.
|
||||
@@ -142,11 +144,11 @@ Por exemplo:
|
||||
|
||||
Para mais informações sobre como passar dados para o backend (usando `httpx` ou `TestClient`), consulte a [documentação do HTTPX](https://www.python-httpx.org).
|
||||
|
||||
/// info | Informação
|
||||
/// note | Nota
|
||||
|
||||
Observe que o `TestClient` recebe dados que podem ser convertidos para JSON, não para modelos Pydantic.
|
||||
|
||||
Se você tiver um modelo Pydantic em seu teste e quiser enviar seus dados para o aplicativo durante o teste, poderá usar o `jsonable_encoder` descrito em [Codificador compatível com JSON](encoder.md).
|
||||
Se você tiver um modelo Pydantic em seu teste e quiser enviar seus dados para a aplicação durante o teste, poderá usar o `jsonable_encoder` descrito em [Codificador compatível com JSON](encoder.md).
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ Se você estiver pronto para adotar uma **ferramenta que gerencia tudo** para vo
|
||||
|
||||
///
|
||||
|
||||
## Criar um Projeto { #create-a-project }
|
||||
## Crie um Projeto { #create-a-project }
|
||||
|
||||
Primeiro, crie um diretório para seu projeto.
|
||||
|
||||
@@ -212,7 +212,7 @@ Se ele mostrar o binário `python` em `.venv\Scripts\python`, dentro do seu proj
|
||||
|
||||
////
|
||||
|
||||
## Atualizar `pip` { #upgrade-pip }
|
||||
## Atualize `pip` { #upgrade-pip }
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
@@ -262,7 +262,7 @@ Esse comando instalará o pip caso ele ainda não esteja instalado e também gar
|
||||
|
||||
///
|
||||
|
||||
## Adicionar `.gitignore` { #add-gitignore }
|
||||
## Adicione `.gitignore` { #add-gitignore }
|
||||
|
||||
Se você estiver usando **Git** (você deveria), adicione um arquivo `.gitignore` para excluir tudo em seu `.venv` do Git.
|
||||
|
||||
@@ -302,7 +302,7 @@ Esse comando criará um arquivo `.gitignore` com o conteúdo:
|
||||
|
||||
///
|
||||
|
||||
## Instalar Pacotes { #install-packages }
|
||||
## Instale Pacotes { #install-packages }
|
||||
|
||||
Após ativar o ambiente, você pode instalar pacotes nele.
|
||||
|
||||
@@ -314,7 +314,7 @@ Se precisar atualizar uma versão ou adicionar um novo pacote, você **fará iss
|
||||
|
||||
///
|
||||
|
||||
### Instalar pacotes diretamente { #install-packages-directly }
|
||||
### Instale pacotes diretamente { #install-packages-directly }
|
||||
|
||||
Se estiver com pressa e não quiser usar um arquivo para declarar os requisitos de pacote do seu projeto, você pode instalá-los diretamente.
|
||||
|
||||
@@ -353,7 +353,7 @@ $ uv pip install "fastapi[standard]"
|
||||
|
||||
////
|
||||
|
||||
### Instalar a partir de `requirements.txt` { #install-from-requirements-txt }
|
||||
### Instale a partir de `requirements.txt` { #install-from-requirements-txt }
|
||||
|
||||
Se você tiver um `requirements.txt`, agora poderá usá-lo para instalar seus pacotes.
|
||||
|
||||
@@ -425,7 +425,7 @@ Normalmente, você só precisa fazer isso **uma vez**, ao criar o ambiente virtu
|
||||
|
||||
///
|
||||
|
||||
## Desativar o ambiente virtual { #deactivate-the-virtual-environment }
|
||||
## Desative o ambiente virtual { #deactivate-the-virtual-environment }
|
||||
|
||||
Quando terminar de trabalhar no seu projeto, você pode **desativar** o ambiente virtual.
|
||||
|
||||
@@ -768,7 +768,7 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python
|
||||
|
||||
Isso significa que o programa `python` que será usado é aquele **no ambiente virtual**.
|
||||
|
||||
você usa `which` no Linux e macOS e `Get-Command` no Windows PowerShell.
|
||||
Você usa `which` no Linux e macOS e `Get-Command` no Windows PowerShell.
|
||||
|
||||
A maneira como esse comando funciona é que ele vai e verifica na variável de ambiente `PATH`, passando por **cada caminho em ordem**, procurando pelo programa chamado `python`. Uma vez que ele o encontre, ele **mostrará o caminho** para esse programa.
|
||||
|
||||
@@ -811,7 +811,7 @@ $ cd ~/code/prisoner-of-azkaban
|
||||
|
||||
$ python main.py
|
||||
|
||||
// Erro ao importar o Sirius, ele não está instalado 😱
|
||||
// Erro ao importar sirius, ele não está instalado 😱
|
||||
Traceback (most recent call last):
|
||||
File "main.py", line 1, in <module>
|
||||
import sirius
|
||||
@@ -861,4 +861,4 @@ Quando estiver pronto e quiser usar uma ferramenta para **gerenciar todo o proje
|
||||
|
||||
Se você leu e entendeu tudo isso, agora **você sabe muito mais** sobre ambientes virtuais do que muitos desenvolvedores por aí. 🤓
|
||||
|
||||
Saber esses detalhes provavelmente será útil no futuro, quando você estiver depurando algo que parece complexo, mas você saberá **como tudo funciona**. 😎
|
||||
Saber esses detalhes provavelmente será útil no futuro, quando você estiver depurando algo que parece complexo, mas você saberá **como tudo funciona por baixo**. 😎
|
||||
|
||||
Reference in New Issue
Block a user