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}