💻 Exemplos: Capítulo 04: Injeção de Dependências no FastAPI (Depends, Annotated)
Especialização em Backend com Python & FastAPI • Demonstrações Práticas Compiláveis
💻 Exemplo 1 — Dependência de Paginação Reaproveitável com Annotated
from typing import Annotated
from fastapi import FastAPI, Depends, Query
app = FastAPI()
def obter_paginacao(
skip: Annotated[int, Query(ge=0, description="Registros a pular")] = 0,
limit: Annotated[int, Query(ge=1, le=100, description="Tamanho máximo da página")] = 20,
) -> dict[str, int]:
return {"skip": skip, "limit": limit}
PaginacaoDep = Annotated[dict[str, int], Depends(obter_paginacao)]
@app.get("/artigos")
async def listar_artigos(pag: PaginacaoDep):
return {"pagina": pag, "itens": []}
@app.get("/comentarios")
async def listar_comentarios(pag: PaginacaoDep):
# Reaproveita a mesma dependência sem repetir validação de skip/limit.
return {"pagina": pag, "itens": []}
💻 Exemplo 2 — Autenticação em Camadas com Sub-dependências e use_cache
import time
from typing import Annotated
from fastapi import FastAPI, Depends, Header, HTTPException, status
app = FastAPI()
def obter_token(authorization: Annotated[str, Header()]) -> str:
if not authorization.startswith("Bearer "):
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "Esquema de autenticação inválido")
return authorization.removeprefix("Bearer ")
def obter_usuario_atual(token: Annotated[str, Depends(obter_token)]) -> dict:
if token != "token-valido-123":
raise HTTPException(status.HTTP_403_FORBIDDEN, "Token inválido ou expirado")
return {"id": 101, "nome": "Ana Souza", "role": "ADMIN"}
def exigir_admin(usuario: Annotated[dict, Depends(obter_usuario_atual)]) -> dict:
if usuario["role"] != "ADMIN":
raise HTTPException(status.HTTP_403_FORBIDDEN, "Recurso restrito a administradores")
return usuario
def marca_temporal(_: Annotated[str, Depends(obter_token, use_cache=False)]) -> float:
# use_cache=False força reavaliação mesmo que obter_token já tenha rodado
# nesta requisição — útil para auditoria com timestamp por chamada.
return time.time()
@app.get("/admin/relatorio")
async def relatorio_admin(
admin: Annotated[dict, Depends(exigir_admin)],
gerado_em: Annotated[float, Depends(marca_temporal)],
):
return {"gerado_por": admin["nome"], "timestamp": gerado_em}
💻 Exemplo 3 — Dependência com yield para Sessão com Rollback Garantido
from typing import Annotated, Iterator
from fastapi import FastAPI, Depends, HTTPException
app = FastAPI()
class SessaoFake:
"""Simula uma sessão de banco com controle transacional explícito."""
def __init__(self) -> None:
self.aberta = True
self.commitada = False
def commit(self) -> None:
self.commitada = True
def rollback(self) -> None:
self.commitada = False
def close(self) -> None:
self.aberta = False
def get_session() -> Iterator[SessaoFake]:
sessao = SessaoFake()
try:
yield sessao
sessao.commit()
except Exception:
sessao.rollback()
raise
finally:
sessao.close()
SessionDep = Annotated[SessaoFake, Depends(get_session)]
@app.post("/pedidos/{pedido_id}/cancelar")
async def cancelar_pedido(pedido_id: int, session: SessionDep):
if pedido_id <= 0:
# A exceção propaga para o "except" da dependência: rollback ocorre
# antes do close(), garantindo que nada fique commitado pela metade.
raise HTTPException(422, "ID de pedido inválido")
return {"pedido_id": pedido_id, "status": "CANCELADO", "commitado": session.commitada}