* Se necessário, melhore seu prompt específico do idioma, o prompt geral ou o documento em inglês.
* 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.
* 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:
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 }
### O abbr fornece uma frase completa { #the-abbr-gives-a-full-phrase }
* <abbrtitle="Getting Things Done – Fazer as Coisas">GTD</abbr>
* <abbrtitle="Getting Things Done - Fazer as Coisas">GTD</abbr>
* <abbrtitle="less than – menos que"><code>lt</code></abbr>
* <abbrtitle="less than - menos que"><code>lt</code></abbr>
* <abbrtitle="XML Web Token – Token Web XML">XWT</abbr>
* <abbrtitle="XML Web Token - Token Web XML">XWT</abbr>
* <abbrtitle="Parallel Server Gateway Interface – Interface de Gateway de Servidor Paralelo">PSGI</abbr>
* <abbrtitle="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 }
### O abbr fornece uma frase completa e uma explicação { #the-abbr-gives-a-full-phrase-and-an-explanation }
* <abbrtitle="Mozilla Developer Network – Rede de Desenvolvedores da Mozilla: documentação para desenvolvedores, escrita pelo pessoal do Firefox">MDN</abbr>
* <abbrtitle="Mozilla Developer Network - Rede de Desenvolvedores da Mozilla: documentação para desenvolvedores, escrita pelo pessoal do Firefox">MDN</abbr>
* <abbrtitle="Input/Output – Entrada/Saída: leitura ou escrita em disco, comunicações de rede.">I/O</abbr>.
* <abbrtitle="Input/Output: leitura ou escrita em disco, comunicações de rede.">I/O</abbr>.
@ -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`.
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 }
## 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).
@ -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).
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.
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**.
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**.
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**.
@ -20,27 +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. 🙇
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 }
## Crie um SDK em TypeScript { #create-a-typescript-sdk }
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 }
### Documentação da API { #api-docs }
@ -72,7 +58,7 @@ Agora você pode importar e usar o código do cliente. Poderia ser assim, observ
...isso ocorre porque o gerador de clientes usa o **ID de operação interno do OpenAPI** para cada *operação de rota*.
...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. 🤓
Mas eu vou te mostrar como melhorar isso a seguir. 🤓
@ -194,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:
Ao usar os clientes gerados automaticamente, você terá **preenchimento automático** para:
* Métodos.
* Métodos.
* Corpos de requisições, parâmetros de query, etc.
* Payloads de requisições no body, parâmetros de query, etc.
@ -4,7 +4,7 @@ Se sua aplicação precisa receber e enviar dados JSON, mas você precisa inclui
## Base64 vs Arquivos { #base64-vs-files }
## 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.
JSON só pode conter strings codificadas em UTF-8, portanto não pode conter bytes puros.
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).
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.
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.
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`.
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).
* 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").
* 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ê:
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.
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:
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 }
## 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**.
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:
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*.
* 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 }
### 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` 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:
Perceba que você não está passando o roteador em si (`invoices_callback_router`) para `callbacks=`, mas o atributo`.routes`, como em `invoices_callback_router.routes`. O FastAPI usará essas rotas para gerar a documentação OpenAPI do callback.
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 }
### 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:
Você verá sua documentação incluindo uma seção "Callbacks" para sua *operação de rota* que mostra como a *API externa* deveria ser:
@ -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.
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á.
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.
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`.
E também que você não esteja enviando nenhum dado que deveria ter sido filtrado por um `response_model`.
Você pode utilizar escopos do OAuth2 diretamente com o **FastAPI**, eles são integrados para funcionar perfeitamente.
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.
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".
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.
Quando um desses esquemas de segurança utiliza OAuth2, você pode também declarar e utilizar escopos.
@ -42,7 +42,7 @@ 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:
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.
* `instagram_basic` é utilizado pelo Facebook / Instagram.
* `https://www.googleapis.com/auth/drive` é utilizado pelo Google.
* `https://www.googleapis.com/auth/drive` é utilizado pelo Google.
@ -60,7 +60,7 @@ Para o OAuth2, eles são apenas strings.
## Visão global { #global-view }
## 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:
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`.
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).
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).
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.
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.
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 }
## 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.
<imgsrc="/img/tutorial/security/image11.png">
<imgsrc="/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.
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.
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.
# Configurações e Variáveis de Ambiente { #settings-and-environment-variables }
# 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.
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.
A maioria dessas configurações é variável (pode mudar), como URLs de banco de dados. E muitas podem ser sensíveis, como segredos.
Se você quer transmitir dados que podem ser estruturados como JSON, você deveria [Transmitir JSON Lines](../tutorial/stream-json-lines.md).
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.
/// note | Nota
/// note | Nota
@ -12,15 +12,15 @@ Adicionado no FastAPI 0.134.0.
## Casos de uso { #use-cases }
## 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 }
## 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.
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 }
### 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 }
## 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.
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
@ -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.
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.
@ -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.
@ -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.
É 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 <abbrtitle="Internet of Things - Internet das Coisas">IoT</abbr>) comunicando com ele.
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 <abbrtitle="Internet of Things - Internet das Coisas">IoT</abbr>) comunicando com ele.
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.
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`
@ -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.
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
* conteúdo que seu programa deu ao sistema para ser escrito no disco
* uma operação em uma API remota
* uma operação em uma API remota
* uma operação no banco de dados finalizar
* 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.
* etc.
Quanto o tempo de execução é consumido majoritariamente pela espera de operações <abbrtitle="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 <abbrtitle="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.
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
@ -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_. 😞
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.
@ -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. 😞
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.
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.
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 }
### 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.
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.
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.
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.
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.
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:
Por exemplo:
* **Processamento de áudio** ou **imagem**
* **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
* **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.
* **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.
* **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 }
### 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).
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).
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"
```Python hl_lines="2-3"
@app.get('/burgers')
@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.
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.
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 }
### 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 }
### 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.
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.
# Conceitos de Implantações { #deployments-concepts }
# 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:
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**.
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. 💡
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.
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.
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.
* 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**.
* 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**.
* 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.
* 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.
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 }
### 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 }
### 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 }
### 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 }
## 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 }
### 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 }
### 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 }
### 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 }
### 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
/// 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 }
### 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 }
## 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.
Mas em muitos casos, você desejará executar vários processos de trabalho ao mesmo tempo.
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**.
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.
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.
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**.
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**.
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.
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:
Aqui estão algumas ideias possíveis:
* Um "Init Container" no Kubernetes que roda antes do seu app container
* 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.
* Você ainda precisaria de uma maneira de iniciar/reiniciar *aquele* script bash, detectar erros, etc.
/// tip | Dica
/// tip | Dica
@ -307,7 +307,7 @@ Você pode usar ferramentas simples como `htop` para ver a CPU e a RAM usadas no
## Recapitular { #recap }
## 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:
@ -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**.
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`.
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.
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)
* [PostgreSQL](https://hub.docker.com/_/postgres)
* [MySQL](https://hub.docker.com/_/mysql)
* [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 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.
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! 🚀
Okay, vamos construir algo agora! 🚀
@ -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 }
#### 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 }
#### 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.
@ -289,7 +289,7 @@ Existe um truque importante nesse `Dockerfile`, primeiro copiamos o **arquivo co
COPY ./requirements.txt /code/requirements.txt
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.
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.
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:
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 <dfntitle="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.
Se você tiver um <dfntitle="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.
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.
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
/// 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 }
### 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**.
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 }
### 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.
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.
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.
@ -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. ⛔️
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).
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).
@ -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.
* 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".
* Esses certificados são na verdade **adquiridos** de um terceiro, eles não são simplesmente "gerados".
* Certificados têm um tempo de vida.
* Certificados têm um **tempo de vida**.
* Eles expiram.
* Eles **expiram**.
* E então eles precisam ser renovados, adquirindo-os novamente de um terceiro.
* E então eles precisam ser **renovados**, **adquiridos novamente** de um terceiro.
* A criptografia da conexão acontece no nível TCP.
* A criptografia da conexão acontece no **nível TCP**.
* Essa é uma camada abaixo do HTTP.
* Essa é uma camada **abaixo do HTTP**.
* Portanto, o manuseio do certificado e da criptografia é feito antes 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.
* **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.
* 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.
* 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.
* **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.
* 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.
* 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).
* 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.
* 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.
* 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.
* **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.
* 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:
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 }
## 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.
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.
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 }
## 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 }
### 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 <dfntitle="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**<dfntitle="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.
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.
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.
### Início do Handshake TLS { #tls-handshake-start }
### 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.
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.
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 }
### 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.
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`.
Nesse caso, ele usaria o certificado para `someapp.example.com`.
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
/// 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 }
### 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.
### Desencripte a Solicitação { #decrypt-the-request }
### 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).
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.
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.
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**.
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 }
### 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).
<imgsrc="/img/deployment/https/https.drawio.svg">
<imgsrc="/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:
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.
* 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.
* 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.
* 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.
* 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 }
## 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
/// 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.
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 }
## 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**. 🔒
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).
Para mais detalhes sobre a extensão, consulte o README no [repositório do GitHub](https://github.com/fastapi/fastapi-vscode).
## Funcionalidades do FastAPI { #fastapi-features }
**FastAPI** te oferece o seguinte:
**FastAPI** te oferece o seguinte:
### Baseado em padrões abertos { #based-on-open-standards }
### 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 <dfntitle="também conhecido como: endpoints, rotas">caminho</dfn><dfntitle="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 <dfntitle="também conhecido como: endpoints, rotas">path</dfn><dfntitle="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).
* 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.
* 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 }
### 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.
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.
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 }
### 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 }
### 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.
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.
* HTTP Basic.
* **OAuth2** (também com **tokens JWT**). Confira o tutorial em [OAuth2 com JWT](tutorial/security/oauth2-jwt.md).
* **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.
* parâmetros da Query.
* Cookies etc.
* 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 }
### 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.
* 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**.
* 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.
* **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.
* **Sem comprometer** os bancos de dados, frontends etc. Mas fácil integração com todos eles.
### "Plug-ins" ilimitados { #unlimited-plug-ins }
### "Plug-ins" ilimitados { #unlimited-plug-ins }
Ou, de outra forma, sem a necessidade deles, importe e use o código que precisar.
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 }
### Testado { #tested }
* 100% <dfntitle="A quantidade de código que é testada automaticamente">de cobertura de testes</dfn>.
* 100% <dfntitle="A quantidade de código que é testada automaticamente">de cobertura de testes</dfn>.
* 100% do código com<dfntitle="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%<dfntitle="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.
* 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** é 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.
`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).
* 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**.
* Suporte a **WebSocket**.
* Tarefas em processo background.
* Tarefas em processo background.
* Eventos na inicialização e encerramento.
* Eventos de inicialização e encerramento.
* Cliente de testes construído sobre HTTPX.
* Cliente de testes construído sobre HTTPX.
* Respostas em **CORS**, GZip, Static Files, Streaming.
## 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á.
**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**.
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 pegadinhas**:
* Sem novas definições de esquema de micro-linguagem para aprender.
* 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 }
## 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). 👀
@ -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)).
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.
@ -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.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
/// 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**.
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 }
### 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.
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á.
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 }
### 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
/// tip | Dica
Primeiro tente com o `bump-pydantic`, se seus testes passarem e isso funcionar, então você concluiu tudo com um único comando. ✨
Primeiro tente com o `bump-pydantic`, se seus testes passarem e isso funcionar, então você concluiu tudo com um único comando. ✨
# Esquemas OpenAPI Separados para Entrada e Saída ou Não { #separate-openapi-schemas-for-input-and-output-or-not }
# 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. 😎
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**.
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**.
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:
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%. *
* **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). *
* **Poucos bugs**: Reduz cerca de 40% de erros induzidos por humanos (desenvolvedores). *
* **Intuitivo**: Grande suporte a editores. <dfntitle="também conhecido como: autocompletar, preenchimento automático, IntelliSense">Completação</dfn> em todos os lugares. Menos tempo debugando.
* **Intuitivo**: Grande suporte a editores. <dfntitle="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.
* **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.
* **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/).
* **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/).
# Full Stack FastAPI Template { #full-stack-fastapi-template }
# 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ê.
- 📞 [Traefik](https://traefik.io) como proxy reverso / balanceador de carga.
- 📞 [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.
- 🚢 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.
# Introdução aos tipos Python { #python-types-intro }
# 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 <dfntitle="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 <dfntitle="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.
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
/// 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`.
* Pega um `first_name` e `last_name`.
* Converte a primeira letra de cada uma em maiúsculas com `title()`.
* Converte a primeira letra de cada uma em maiúsculas com `title()`.
* <dfntitle="Coloca-os juntos, como um só. Com o conteúdo de um após o outro.">Concatena</dfn> com um espaço no meio.
* <dfntitle="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.
Mas agora imagine que você estava escrevendo do zero.
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`?
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.
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:
<imgsrc="/img/python-types/image04.png">
<imgsrc="/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 }
## 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 }
### Tipos simples { #simple-types }
@ -137,7 +137,7 @@ Você pode usar, por exemplo:
### Módulo `typing` { #typing-module }
### 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`:
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**.
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`
* `list`
* `tuple`
* `tuple`
@ -168,7 +168,7 @@ Declare a variável, com a mesma sintaxe com dois pontos (`:`).
Como o tipo, coloque `list`.
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:
* As chaves deste `dict` são do tipo `str` (digamos, o nome de cada item).
* 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.
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.
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
/// 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).
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 **<dfntitle="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 **<dfntitle="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`.
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.
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. 😎
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:
Isso significa que o **FastAPI** vai esperar um corpo similar à:
Isso significa que o **FastAPI** vai esperar um corpo similar a:
```JSON
```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.
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`:
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 }
## Atributos como listas de submodelos { #attributes-with-lists-of-submodels }
@ -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 }
## 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
```Python
images: list[Image]
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.
É 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`:
@ -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.
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:
Mas com todos os benefícios:
* Suporte do editor (preenchimento automático em todo canto!)
* 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)
@ -115,7 +115,7 @@ Se você quiser capturar exceções e criar uma resposta personalizada com base
## Dependências com `yield` e `except` { #dependencies-with-yield-and-except }
## 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:
@ -123,7 +123,7 @@ Neste caso, o cliente irá ver uma resposta *HTTP 500 Internal Server Error* com
### Sempre `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`:
Você pode relançar a mesma exceção utilizando `raise`:
@ -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:
`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.
* `"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.
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.
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).
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 }
## Gerenciadores de contexto { #context-managers }
### O que são "Gerenciadores de Contexto" { #what-are-context-managers }
### O que são "Gerenciadores de Contexto" { #what-are-context-managers }
@ -36,19 +36,19 @@ Aqui estão alguns dos tipos de dados adicionais que você pode usar:
* `datetime.timedelta`:
* `datetime.timedelta`:
* O `datetime.timedelta` do Python.
* O `datetime.timedelta` do Python.
* Em requisições e respostas será representado como um `float` de segundos totais.
* 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`:
* `frozenset`:
* Em requisições e respostas, será tratado da mesma forma que um `set`:
* 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`.
* 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).
* O esquema gerado vai especificar que os valores do `set` são únicos (usando o `uniqueItems` do JSON Schema).
* `bytes`:
* `bytes`:
* O `bytes` padrão do Python.
* 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`.
* O esquema gerado vai especificar que é uma `str` com o "formato" `binary`.
* `Decimal`:
* `Decimal`:
* O `Decimal` padrão do Python.
* 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/).
* 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/).
@ -208,4 +208,4 @@ Neste caso, você pode usar `dict`:
Use vários modelos Pydantic e herde livremente para cada caso.
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 }
### 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.
Nesse caso, significaria os atributos JSON e os tipos de dados que eles possuem, etc.
#### OpenAPI e JSON Schema { #openapi-and-json-schema }
#### 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 }
#### 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).
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 }
#### 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**.
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 }
### Configure o `entrypoint` da aplicação em `pyproject.toml` { #configure-the-app-entrypoint-in-pyproject-toml }
@ -244,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.
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 }
#### Path { #path }
@ -305,14 +305,14 @@ Portanto, no OpenAPI, cada um dos métodos HTTP é chamado de "operação".
Vamos chamá-los de "**operações**" também.
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 }
O `@app.get("/")` diz ao **FastAPI** que a função logo abaixo é responsável por tratar as requisições que vão para:
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 `/`
* o path `/`
* usando uma <dfntitle="um método HTTP GET"><code>get</code> operação</dfn>
* usando uma <dfntitle="um método HTTP GET">operação <code>get</code></dfn>
/// note | Informações sobre `@decorator`
/// note | Informações sobre `@decorator`
@ -387,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ê 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.
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.
@ -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:
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 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.
* 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.
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 }
## 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`.
### 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.
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`:
### A response resultante { #the-resulting-response }
### 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
```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
```JSON
{
{
@ -62,38 +61,41 @@ Mas se o cliente faz uma requisição para `http://example.com/items/bar` (ou se
/// tip | Dica
/// 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`, uma `list`, etc.
Você pode passar um `dict` ou um `list`, etc.
Eles são manipulados automaticamente pelo **FastAPI** e convertidos para JSON.
Esses tipos de dados são manipulados automaticamente pelo **FastAPI** e convertidos em JSON.
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:
## Instale manipuladores de exceções customizados { #install-custom-exception-handlers }
## 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ê usa) possa lançar com `raise`.
Digamos que você tenha uma exceção customizada `UnicornException` que você (ou uma biblioteca que você use) precise lançar (`raise`).
E você quer manipular essa exceção globalmente com o FastAPI.
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()`.
Você poderia adicionar um manipulador de exceção customizado com `@app.exception_handler()`:
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
```JSON
{"message": "Oops! yolo did something. There goes a rainbow..."}
{"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`.
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.
**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.
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.
O manipulador de exceções receberá um `Request` e a exceção.
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.
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.
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 }
### 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.
@ -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"
```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
```Python
from starlette.exceptions import HTTPException as StarletteHTTPException
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 }
### 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`:
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.
# Tutorial - Guia de Usuário { #tutorial-user-guide }
# 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.
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.
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).
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`:
<divclass="termy">
<divclass="termy">
@ -52,9 +52,9 @@ $ <font color="#4E9A06">fastapi</font> dev
</div>
</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**.
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).
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. |
| `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> |
| `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. |
| `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. |
| `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> |
| `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> |
| `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> |
@ -80,7 +80,7 @@ Leia mais sobre tags em [Configuração de operação de rota](path-operation-co
///
///
### 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:
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 }
### 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`.
Nestes casos, pode fazer sentido armazenar as tags em um `Enum`.
@ -18,7 +18,7 @@ Ter `str | None` permitirá que seu editor lhe ofereça melhor suporte e detecte
## Validação adicional { #additional-validation }
## 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 }
### Importe `Query` e `Annotated` { #import-query-and-annotated }
@ -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.
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
/// 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:
Agora o FastAPI vai:
* Validar os dados garantindo que o comprimento máximo seja de 50 caracteres
* **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
* 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)
* **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 }
## 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 `
### Vantagens de `Annotated` { #advantages-of-annotated }
### 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/). 🚀
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`:
Você pode definir um `pattern` de <dfntitle="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 <dfntitle="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:
@ -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`.
* `fixedquery`: tem exatamente o valor `fixedquery`.
* `$`: termina ali, não tem mais caracteres depois de `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 }
## Valores padrão { #default-values }
@ -242,7 +242,7 @@ Então, com uma URL como:
http://localhost:8000/items/?q=foo&q=bar
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:
Assim, a resposta para essa URL seria:
@ -360,15 +360,15 @@ A documentação vai mostrar assim:
## Excluir parâmetros do OpenAPI { #exclude-parameters-from-openapi }
## 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`:
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`.
Você pode fazer isso usando o [`AfterValidator` do Pydantic](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) dentro de `Annotated`.
@ -390,15 +390,15 @@ Isso está disponível com a versão 2 do Pydantic ou superior. 😎
/// tip | Dica
/// 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 }
### 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. 🤸
---
---
@ -416,13 +416,13 @@ Com `data.items()` obtemos um <dfn title="Algo que podemos iterar com um laço f
Convertemos 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.
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? 🐍
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`.
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 }
## 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ê.
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
@ -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".
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.
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.
* 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.
* 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.
* 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 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) que você pode passar diretamente para outras bibliotecas que esperam um objeto semelhante a um arquivo.
* 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 }
### `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`).
* `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`).
* `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.
* `write(data)`: Escreve `data` (`str` ou `bytes`) no arquivo.
* `read(size)`: Lê `size` (`int`) bytes/caracteres do 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.
* Isso é especialmente útil se você executar `await myfile.read()` uma vez e precisar ler o conteúdo novamente.
* `close()`: Fecha o arquivo.
* `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
```Python
contents = await myfile.read()
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
```Python
contents = myfile.file.read()
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.
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.
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).
@ -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.
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).
@ -12,7 +12,7 @@ Da mesma forma que você pode especificar um modelo de resposta, você também p
/// note | Nota
/// 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.
///
///
@ -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.
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`.
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.
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.
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.
* 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).
* 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 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.
* O frontend precisa buscar mais dados da API.
* Mas precisa de autenticação para aquele endpoint específico.
* 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.
* Então, para autenticar com nossa API, ele envia um header `Authorization` com o valor `Bearer ` mais o token.
@ -144,7 +144,7 @@ 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.
Em breve também criaremos a operação de rota real.
# OAuth2 com Senha (e hashing), Bearer com tokens JWT { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }
# 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 <abbrtitle="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 <abbrtitle="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.
Este código é algo que você pode realmente usar na sua aplicação, salvar os hashes das senhas no seu banco de dados, etc.
@ -44,7 +44,7 @@ $ pip install pyjwt
/// note | Nota
/// note | Nota
Se você pretende 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).
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.
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.
E seus usuários poderiam fazer login tanto pela sua aplicação Django quanto pela sua aplicação **FastAPI**, ao mesmo tempo.
@ -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.
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.
@ -6,7 +6,7 @@ Agora vamos construir a partir do capítulo anterior e adicionar as partes que f
Vamos usar os utilitários 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.
E a especificação diz que os campos devem ser nomeados assim. Portanto, `user-name` ou `email` não funcionariam.
@ -29,7 +29,7 @@ Cada “scope” é apenas uma string (sem espaços).
Normalmente são usados para declarar permissões de segurança específicas, por exemplo:
Normalmente são usados para declarar permissões de segurança específicas, por exemplo:
* `users:read` ou `users:write` são exemplos comuns.
* `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.
* `https://www.googleapis.com/auth/drive` é usado pelo Google.
/// note | Nota
/// note | Nota
@ -78,7 +78,7 @@ O `OAuth2PasswordRequestForm` não é uma classe especial para **FastAPI** como
`OAuth2PasswordBearer` faz com que **FastAPI** saiba que é um esquema de segurança. Portanto, é adicionado dessa forma ao OpenAPI.
`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.
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.
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.
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.
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 }
##### Porque 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.
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.
@ -146,7 +146,7 @@ UserInDB(
/// note | Nota
/// note | Nota
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).
Aqui veremos um exemplo usando [SQLModel](https://sqlmodel.tiangolo.com/).
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
/// 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/).
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`:
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>
</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**.
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. 🤓
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:
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).
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.
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.
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.
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*.
Em seguida, adicionamos uma função que usa `SQLModel.metadata.create_all(engine)` para **criar as tabelas** para todos os *modelos de tabela*.
### 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.
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
### 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.
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.
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.
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.
Podemos **ler**`Hero`s do banco de dados usando um `select()`. Podemos incluir um `limit` e `offset` para paginar os resultados.
## 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**.
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**... 😅
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. ✨
Vamos corrigir essas coisas adicionando alguns **modelos extras**. Aqui é onde o SQLModel vai brilhar. ✨
### 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.
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.
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.
@ -52,7 +52,7 @@ Você também pode usar `from starlette.testclient import TestClient`.
/// tip | Dica
/// 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
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.
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.
Depois é só fazer o mesmo nos seus testes.
@ -146,7 +148,7 @@ Para mais informações sobre como passar dados para o backend (usando `httpx` o
Observe que o `TestClient` recebe dados que podem ser convertidos para JSON, não para modelos Pydantic.
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).
Isso significa que o programa `python` que será usado é aquele **no ambiente virtual**.
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.
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
$ 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):
Traceback (most recent call last):
File "main.py", line 1, in <module>
File "main.py", line 1, in <module>
import sirius
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í. 🤓
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**. 😎