Capítulo 04: Injeção de Dependências no FastAPI (Depends, Annotated)
Especialização em Backend com Python & FastAPI • FastAPI & Python 3.12+ • Pydantic v2, SQLModel, Async/Await e Microsserviços
🗺️ Mapa Conceitual do Tópico
flowchart TD
A["Cliente HTTP / Frontend"] --> B["API Gateway / Router"]
B --> C["Controller / Handler"]
C --> D["Service Layer (Regras de Negócio)"]
D --> E["Repository / ORM (Persistência)"]
E --> F["Banco de Dados / Cache"]
subgraph ARQ["Arquitetura do Capítulo"]
G["Conceito: Injeção de Dependências no FastAPI (Depends, Annotated)"]
H["Segurança, Validação e Resiliência"]
I["Alta Performance e Escalabilidade"]
end
D --> ARQ
style A fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px
style B fill:#fff3e0,stroke:#ff9800,stroke-width:2px
style C fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
style D fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
style E fill:#fce4ec,stroke:#e91e63,stroke-width:2px
style F fill:#f3e5f5,stroke:#9c27b0,stroke-width:2px
🏛️ 1. Depends como padrão de Injeção de Dependências
O sistema de dependências do FastAPI é o mecanismo que permite compartilhar lógica reutilizável entre endpoints — autenticação, paginação, conexões de banco, filtros — sem duplicar código nem acoplar handlers diretamente a implementações concretas. Uma dependência é simplesmente uma função ou classe chamável (callable) que o FastAPI executa antes do handler e cujo valor de retorno é injetado como parâmetro. A grande vantagem sobre chamar a função diretamente dentro do endpoint é que Depends participa do sistema de validação e documentação automática do OpenAPI, e pode ser sobrescrita em testes via app.dependency_overrides, sem precisar de mocks complexos.
from typing import Annotated
from fastapi import FastAPI, Depends, Query
app = FastAPI()
def obter_paginacao(
skip: Annotated[int, Query(ge=0)] = 0,
limit: Annotated[int, Query(ge=1, le=100)] = 20,
) -> dict:
return {"skip": skip, "limit": limit}
@app.get("/artigos")
async def listar_artigos(pag: Annotated[dict, Depends(obter_paginacao)]):
return {"pagina": pag, "itens": []}
A forma Annotated[Tipo, Depends(...)] é a sintaxe recomendada desde o FastAPI 0.95: ela separa o tipo da metainformação de origem do valor, o que é reaproveitável em múltiplos parâmetros e compatível com ferramentas de análise estática de tipos, ao contrário do antigo param: Tipo = Depends(...).
Dependências baseadas em classe
Quando a dependência precisa manter múltiplos atributos relacionados (não apenas um valor único), uma classe é mais expressiva que uma função. Depends() sem argumento, aplicado a um parâmetro anotado com a própria classe, instrui o FastAPI a instanciar a classe usando seu __init__ como se fosse a assinatura da dependência — cada parâmetro do construtor vira um query parameter validado automaticamente.
from typing import Optional
from fastapi import FastAPI, Depends
class FiltroAuditoria:
def __init__(self, autor: Optional[str] = None, status: str = "ATIVO"):
self.autor = autor
self.status = status
app = FastAPI()
@app.get("/logs")
async def buscar_logs(filtro: FiltroAuditoria = Depends()):
return {"autor_filtrado": filtro.autor, "status": filtro.status}
Sub-dependências (dependências encadeadas)
Dependências podem depender de outras dependências, formando uma árvore de resolução que o FastAPI resolve automaticamente, de baixo para cima. Isso viabiliza pipelines de autenticação em camadas: extrair o token do header, validar o token, e só então carregar o usuário — cada etapa isolada e testável separadamente.
from fastapi import FastAPI, Depends, HTTPException, Header
app = FastAPI()
def obter_token(authorization: str = Header(...)) -> str:
if not authorization.startswith("Bearer "):
raise HTTPException(status_code=401)
return authorization.split(" ")[1]
def obter_usuario_logado(token: str = Depends(obter_token)) -> dict:
if token != "secret_token_123":
raise HTTPException(status_code=403)
return {"user_id": 101, "role": "ADMIN"}
@app.get("/me")
async def get_me(current_user: dict = Depends(obter_usuario_logado)):
return {"usuario": current_user}
Por padrão, o FastAPI faz cache do resultado de uma dependência dentro do escopo de uma única requisição — se duas rotas ou dois parâmetros do mesmo endpoint dependem de obter_token, a função roda apenas uma vez. Esse comportamento pode ser desligado com Depends(obter_token, use_cache=False) quando o valor precisa ser recalculado (por exemplo, um timestamp de auditoria).
Dependências com yield: setup e teardown garantidos
Quando a dependência precisa liberar um recurso depois que a resposta é enviada (fechar uma sessão de banco, devolver uma conexão a um pool), usa-se yield em vez de return. O código antes do yield roda como setup; o código depois — dentro de um try/finally — roda como teardown, mesmo que o handler levante uma exceção, garantindo que a sessão nunca vaze.
from fastapi import FastAPI, Depends
app = FastAPI()
async def get_db_session():
print("LOG: Conexão com banco aberta")
db = {"status": "conectado", "id": 42}
try:
yield db
finally:
print("LOG: Conexão com banco encerrada com sucesso")
@app.get("/transacao")
async def executar_transacao(db: dict = Depends(get_db_session)):
return {"db_id": db["id"], "resultado": "OK"}
🔗 Recursos Pedagógicos do Capítulo 04
| Recurso Didático | Finalidade | Link de Acesso |
|---|---|---|
| 📊 Slides de Aula | Apresentação visual interativa com Dark Mode e suporte a teclado | Ver Slides |
| 🧠 Quiz Formativo | Teste interativo de fixação com feedback imediato por alternativa | Fazer Quiz |
| 💻 Exemplos de Código | Demonstrações funcionais com código executável | Ver Exemplos |
| 🧩 Exercícios em 4 Níveis | Lista progressiva de fixação com gabarito em bloco colapsável | Resolver Exercícios |
| ⬅️ Capítulo Anterior | 📚 Sumário de Tópicos | Próximo Capítulo ➡️ |