Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
349 changes: 349 additions & 0 deletions docs/pt/docs/tutorial/dependencies/dependencies-with-yield.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,349 @@
# DependĂȘncias com yield

O FastAPI possui suporte para dependĂȘncias que realizam <abbr title='tambĂ©m chamados de "cĂłdigo de saĂ­da", "cĂłdigo de cleanup", "cĂłdigo de teardown", "cĂłdigo de finalização", "cĂłdigo de saĂ­da para gerenciador de contextos", etc.'>alguns passos extras ao finalizar</abbr>.

Para fazer isso, utilize `yield` em vez de `return`, e escreva os passos extras (cĂłdigo) depois.

!!! tip "Dica"
Garanta que `yield` Ă© utilizado apenas uma vez.

!!! note "Detalhes Técnicos"
Qualquer função que possa ser utilizada com:

* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" class="external-link" target="_blank">`@contextlib.contextmanager`</a> ou
* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager" class="external-link" target="_blank">`@contextlib.asynccontextmanager`</a>

pode ser utilizada como uma dependĂȘncia do **FastAPI**.

Na realidade, o FastAPI utiliza esses dois decoradores internamente.

## Uma dependĂȘncia de banco de dados com `yield`

Por exemplo, vocĂȘ poderia utilizar isso para criar uma sessĂŁo do banco de dados, e fechĂĄ-la apĂłs terminar sua operação.

Apenas o código anterior a declaração com `yield` e o código contendo essa declaração são executados antes de criar uma resposta.

```Python hl_lines="2-4"
{!../../../docs_src/dependencies/tutorial007.py!}
```

O valor gerado (yielded) Ă© o que Ă© injetado nas *operaçÔes de rota* e outras dependĂȘncias.

```Python hl_lines="4"
{!../../../docs_src/dependencies/tutorial007.py!}
```

O cĂłdigo apĂłs o `yield` Ă© executado apĂłs a resposta ser entregue:

```Python hl_lines="5-6"
{!../../../docs_src/dependencies/tutorial007.py!}
```

!!! tip "Dica"
VocĂȘ pode usar funçÔes assĂ­ncronas (`async`) ou funçÔes comuns.

O **FastAPI** saberĂĄ o que fazer com cada uma, da mesma forma que as dependĂȘncias comuns.

## Uma dependĂȘncia com `yield` e `try`

Se vocĂȘ utilizar um bloco `try` em uma dependĂȘncia com `yield`, vocĂȘ irĂĄ capturar qualquer exceção que for lançada enquanto a dependĂȘncia Ă© utilizada.

Por exemplo, se algum cĂłdigo em um certo momento no meio da operação, em outra dependĂȘncia ou em uma *operação de rota*, fizer um "rollback" de uma transação de banco de dados ou causar qualquer outro erro, vocĂȘ irĂĄ capturar a exceção em sua dependĂȘncia.

EntĂŁo, vocĂȘ pode procurar por essa exceção especĂ­fica dentro da dependĂȘncia com `except AlgumaExcecao`.

Da mesma forma, vocĂȘ pode utilizar `finally` para garantir que os passos de saĂ­da sĂŁo executados, com ou sem exceçÔes.

```python hl_lines="3 5"
{!../../../docs_src/dependencies/tutorial007.py!}
```

## SubdependĂȘncias com `yield`

VocĂȘ pode ter subdependĂȘncias e "ĂĄrvores" de subdependĂȘncias de qualquer tamanho e forma, e qualquer uma ou todas elas podem utilizar `yield`.

O **FastAPI** garantirĂĄ que o "cĂłdigo de saĂ­da" em cada dependĂȘncia com `yield` Ă© executado na ordem correta.

Por exemplo, `dependency_c` pode depender de `dependency_b`, e `dependency_b` depender de `dependency_a`:

=== "python 3.9+"

```python hl_lines="6 14 22"
{!> ../../../docs_src/dependencies/tutorial008_an_py39.py!}
```

=== "python 3.8+"

```python hl_lines="5 13 21"
{!> ../../../docs_src/dependencies/tutorial008_an.py!}
```

=== "python 3.8+ non-annotated"

!!! tip "Dica"
Utilize a versĂŁo com `Annotated` se possĂ­vel.

```python hl_lines="4 12 20"
{!> ../../../docs_src/dependencies/tutorial008.py!}
```

E todas elas podem utilizar `yield`.

Neste caso, `dependency_c` precisa que o valor de `dependency_b` (nomeada de `dep_b` aqui) continue disponĂ­vel para executar seu cĂłdigo de saĂ­da.

E, por outro lado, `dependency_b` precisa que o valor de `dependency_a` (nomeada de `dep_a`) continue disponĂ­vel para executar seu cĂłdigo de saĂ­da.

=== "python 3.9+"

```python hl_lines="18-19 26-27"
{!> ../../../docs_src/dependencies/tutorial008_an_py39.py!}
```

=== "python 3.8+"

```python hl_lines="17-18 25-26"
{!> ../../../docs_src/dependencies/tutorial008_an.py!}
```

=== "python 3.8+ non-annotated"

!!! tip "Dica"
Utilize a versĂŁo com `Annotated` se possĂ­vel.

```python hl_lines="16-17 24-25"
{!> ../../../docs_src/dependencies/tutorial008.py!}
```

Da mesma forma, vocĂȘ pode ter algumas dependĂȘncias com `yield` e outras com `return` e ter uma relação de dependĂȘncia entre algumas dos dois tipos.

E vocĂȘ poderia ter uma Ășnica dependĂȘncia que precisa de diversas outras dependĂȘncias com `yield`, etc.

VocĂȘ pode ter qualquer combinação de dependĂȘncias que vocĂȘ quiser.

O **FastAPI** se encarrega de executĂĄ-las na ordem certa.

!!! note "Detalhes Técnicos"
Tudo isso funciona graças aos <a href="https://docs.python.org/3/library/contextlib.html" class="external-link" target="_blank">gerenciadores de contexto</a> do Python.

O **FastAPI** utiliza eles internamente para alcançar isso.

## DependĂȘncias com `yield` e `httpexception`

VocĂȘ viu que dependĂȘncias podem ser utilizadas com `yield` e podem incluir blocos `try` para capturar exceçÔes.

Da mesma forma, vocĂȘ pode lançar uma `httpexception` ou algo parecido no cĂłdigo de saĂ­da, apĂłs o `yield`

!!! tip "Dica"

Essa Ă© uma tĂ©cnica relativamente avançada, e na maioria dos casos vocĂȘ nĂŁo precisa dela totalmente, jĂĄ que vocĂȘ pode lançar exceçÔes (incluindo `httpexception`) dentro do resto do cĂłdigo da sua aplicação, por exemplo, em uma *função de operação de rota*.

Mas ela existe para ser utilizada caso vocĂȘ precise. đŸ€“

=== "python 3.9+"

```python hl_lines="18-22 31"
{!> ../../../docs_src/dependencies/tutorial008b_an_py39.py!}
```

=== "python 3.8+"

```python hl_lines="17-21 30"
{!> ../../../docs_src/dependencies/tutorial008b_an.py!}
```

=== "python 3.8+ non-annotated"

!!! tip "Dica"
Utilize a versĂŁo com `Annotated` se possĂ­vel.

```python hl_lines="16-20 29"
{!> ../../../docs_src/dependencies/tutorial008b.py!}
```

Uma alternativa que vocĂȘ pode utilizar para capturar exceçÔes (e possivelmente lançar outra HTTPException) Ă© criar um [Manipulador de ExceçÔes Customizado](../handling-errors.md#instalando-manipuladores-de-excecoes-customizados){.internal-link target=_blank}.

## DependĂȘncias com `yield` e `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 identifcar que houve uma exceção, da mesma forma que aconteceria com Python puro:

=== "Python 3.9+"

```Python hl_lines="15-16"
{!> ../../../docs_src/dependencies/tutorial008c_an_py39.py!}
```

=== "Python 3.8+"

```Python hl_lines="14-15"
{!> ../../../docs_src/dependencies/tutorial008c_an.py!}
```

=== "Python 3.8+ non-annotated"

!!! tip "dica"
utilize a versĂŁo com `Annotated` se possĂ­vel.

```Python hl_lines="13-14"
{!> ../../../docs_src/dependencies/tutorial008c.py!}
```

Neste caso, o cliente irĂĄ ver uma resposta *HTTP 500 Internal Server Error* como deveria acontecer, jĂĄ que nĂŁo estamos levantando nenhuma `HTTPException` ou coisa parecida, mas o servidor **nĂŁo terĂĄ nenhum log** ou qualquer outra indicação de qual foi o erro. đŸ˜±

### Sempre levante (`raise`) exceçÔes em DependĂȘncias com `yield` e `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ĂȘ deveria relançar a exceção original.

VocĂȘ pode relançar a mesma exceção utilizando `raise`:

=== "Python 3.9+"

```Python hl_lines="17"
{!> ../../../docs_src/dependencies/tutorial008d_an_py39.py!}
```

=== "Python 3.8+"

```Python hl_lines="16"
{!> ../../../docs_src/dependencies/tutorial008d_an.py!}
```

=== "python 3.8+ non-annotated"

!!! tip "Dica"
Utilize a versĂŁo com `Annotated` se possĂ­vel.

```Python hl_lines="15"
{!> ../../../docs_src/dependencies/tutorial008d.py!}
```

Agora o cliente irá receber a mesma resposta *HTTP 500 Internal Server Error*, mas o servidor terá nosso `InternalError` personalizado nos logs. 😎

## Execução de dependĂȘncias com `yield`

A sequĂȘncia de execução Ă© mais ou menos como esse diagrama. O tempo passa do topo para baixo. E cada coluna Ă© uma das partes interagindo ou executando cĂłdigo.

```mermaid
sequenceDiagram

participant client as Cliente
participant handler as Manipulador de exceçÔes
participant dep as Dep com yield
participant operation as Operação de Rota
participant tasks as Tarefas de Background

Note over client,operation: pode lançar exceçÔes, incluindo HTTPException
client ->> dep: Iniciar requisição
Note over dep: Executar código até o yield
opt lançar Exceção
dep -->> handler: lançar Exceção
handler -->> client: resposta de erro HTTP
end
dep ->> operation: Executar dependĂȘncia, e.g. sessĂŁo de BD
opt raise
operation -->> dep: Lançar exceção (e.g. HTTPException)
opt handle
dep -->> dep: Pode capturar exceçÔes, lançar uma nova HTTPException, lançar outras exceçÔes
end
handler -->> client: resposta de erro HTTP
end

operation ->> client: Retornar resposta ao cliente
Note over client,operation: Resposta jĂĄ foi enviada, e nĂŁo pode ser modificada
opt Tarefas
operation -->> tasks: Enviar tarefas de background
end
opt Lançar outra exceção
tasks -->> tasks: Manipula exceçÔes no código da tarefa de background
end
```

!!! info "Informação"
Apenas **uma resposta** serå enviada para o cliente. Ela pode ser uma das respostas de erro, ou então a resposta da *operação de rota*.

ApĂłs uma dessas respostas ser enviada, nenhuma outra resposta pode ser enviada

!!! tip "Dica"
Esse diagrama mostra `HttpException`, mas vocĂȘ pode levantar qualquer outra exceção que vocĂȘ capture em uma dependĂȘncia com `yield` ou um [Manipulador de exceçÔes personalizado](../handling-errors.md#instalando-manipuladores-de-excecoes-customizados){.internal-link target=_blank}.

Se vocĂȘ lançar qualquer exceção, ela serĂĄ passada para as dependĂȘncias com yield, inlcuindo a `HTTPException`. Na maioria dos casos vocĂȘ vai querer relançar essa mesma exceção ou uma nova a partir da dependĂȘncia com `yield` para garantir que ela seja tratada adequadamente.

## DependĂȘncias com `yield`, `HTTPException`, `except` e Tarefas de Background

!!! warning "Aviso"
VocĂȘ provavelmente nĂŁo precisa desses detalhes tĂ©cnicos, vocĂȘ pode pular essa seção e continuar na prĂłxima seção abaixo.

Esses detalhes sĂŁo Ășteis principalmente se vocĂȘ estiver usando uma versĂŁo do FastAPI anterior Ă  0.106.0 e utilizando recursos de dependĂȘncias com `yield` em tarefas de background.

### DependĂȘncias com `yield` e `except`, Detalhes TĂ©cnicos

Antes do FastAPI 0.110.0, se vocĂȘ utilizasse uma dependĂȘncia com `yield`, e entĂŁo capturasse uma dependĂȘncia com `except` nessa dependĂȘncia, caso a exceção nĂŁo fosse relançada, ela era automaticamente lançada para qualquer manipulador de exceçÔes ou o manipulador de erros interno do servidor.

Isso foi modificado na versão 0.110.0 para consertar o consumo de memória não controlado das exceçÔes relançadas automaticamente sem um manipulador (erros internos do servidor), e para manter o comportamento consistente com o código Python tradicional.

### Tarefas de Background e DependĂȘncias com `yield`, Detalhes TĂ©cnicos

Antes do FastAPI 0.106.0, levantar exceçÔes apĂłs um `yield` nĂŁo era possĂ­vel, o cĂłdigo de saĂ­da nas dependĂȘncias com `yield` era executado *apĂłs* a resposta ser enviada, entĂŁo os [Manipuladores de ExceçÔes](../handling-errors.md#instalando-manipuladores-de-excecoes-customizados){.internal-link target=_blank} jĂĄ teriam executado.

Isso foi implementado dessa forma principalmente para permitir que os mesmos objetos fornecidos ("yielded") pelas dependĂȘncias dentro de tarefas de background fossem reutilizados, por que o cĂłdigo de saĂ­da era executado antes das tarefas de background serem finalizadas.

Ainda assim, como isso exigiria esperar que a resposta navegasse pela rede enquanto mantia ativo um recurso desnecessĂĄrio na dependĂȘncia com yield (por exemplo, uma conexĂŁo com banco de dados), isso mudou na versĂŁo 0.106.0 do FastAPI.

!!! tip "Dica"

Adicionalmente, uma tarefa de background Ă©, normalmente, um conjunto de lĂłgicas independentes que devem ser manipuladas separadamente, com seus prĂłprios recursos (e.g. sua prĂłpria conexĂŁo com banco de dados).

EntĂŁo, dessa forma vocĂȘ provavelmente terĂĄ um cĂłdigo mais limpo.

Se vocĂȘ costumava depender desse comportamento, agora vocĂȘ precisa criar os recursos para uma tarefa de background dentro dela mesma, e usar internamente apenas dados que nĂŁo dependam de recursos de dependĂȘncias com `yield`.

Por exemplo, em vez de utilizar a mesma sessĂŁo do banco de dados, vocĂȘ criaria uma nova sessĂŁo dentro da tarefa de background, e vocĂȘ obteria os objetos do banco de dados utilizando essa nova sessĂŁo. E entĂŁo, em vez de passar o objeto obtido do banco de dados como um parĂąmetro para a função da tarefa de background, vocĂȘ passaria o ID desse objeto e buscaria ele novamente dentro da função da tarefa de background.

## Gerenciadores de contexto

### O que sĂŁo gerenciadores de contexto

"Gerenciadores de Contexto" são qualquer um dos objetos Python que podem ser utilizados com a declaração `with`.

Por exemplo, <a href="https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files" class="external-link" target="_blank">vocĂȘ pode utilizar `with` para ler um arquivo</a>:

```Python
with open("./somefile.txt") as f:
contents = f.read()
print(contents)
```

Por baixo dos panos, o cĂłdigo `open("./somefile.txt")` cria um objeto que Ă© chamado de "Gerenciador de Contexto".

Quando o bloco `with` finaliza, ele se certifica de fechar o arquivo, mesmo que tenha ocorrido alguma exceção.

Quando vocĂȘ cria uma dependĂȘncia com `yield`, o **FastAPI** irĂĄ criar um gerenciador de contexto internamente para ela, e combinĂĄ-lo com algumas outras ferramentas relacionadas.

### Utilizando gerenciadores de contexto em dependĂȘncias com `yield`

!!! warning "Aviso"
Isso é uma ideia mais ou menos "avançada".

Se vocĂȘ estĂĄ apenas iniciando com o **FastAPI** vocĂȘ pode querer pular isso por enquanto.

Em python, vocĂȘ pode criar Gerenciadores de Contexto ao <a href="https://docs.python.org/3/reference/datamodel.html#context-managers" class="external-link" target="_blank"> criar uma classe com dois mĂ©todos: `__enter__()` e `__exit__()`</a>.

VocĂȘ tambĂ©m pode usĂĄ-los dentro de dependĂȘncias com `yield` do **FastAPI** ao utilizar `with` ou `async with` dentro da função da dependĂȘncia:

```Python hl_lines="1-9 13"
{!../../../docs_src/dependencies/tutorial010.py!}
```

!!! tip "Dica"
Outra forma de criar um gerenciador de contexto Ă© utilizando:

* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager" class="external-link" target="_blank">`@contextlib.contextmanager`</a> ou

* <a href="https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager" class="external-link" target="_blank">`@contextlib.asynccontextmanager`</a>

Para decorar uma função com um Ășnico `yield`.

Isso Ă© o que o **FastAPI** usa internamente para dependĂȘncias com `yield`.

Mas vocĂȘ nĂŁo precisa usar esses decoradores para as dependĂȘncias do FastAPI (e vocĂȘ nĂŁo deveria).

O FastAPI irĂĄ fazer isso para vocĂȘ internamente.