Como versionar uma API de Dados com FastAPI e OpenAPI
Este tutorial mostra como versionar uma API de Dados com FastAPI e OpenAPI de forma prática e útil. Saber versionar uma API permite introduzir alterações sem quebrar clientes, documentar diferenças e gerir migrações com menos risco.
Pré-requisitos
- Python 3.9+ e pip instalados
- Conhecimentos básicos de FastAPI e HTTP
- Editor de código e terminal
Passo 1: preparar o ambiente
Crie um ambiente virtual e instale FastAPI e Uvicorn. Usamos dependências mínimas para focar no versionamento.
python -m venv .venv
source .venv/bin/activate # ou .venv\Scripts\activate no Windows
pip install fastapi uvicorn
Passo 2: criar routers separados por versão (path versioning)
Uma abordagem simples e explícita é usar prefixes como /v1 e /v2. Cada router tem a sua implementação, permitindo alterações internas sem impacto entre versões.
# app/main.py
from fastapi import FastAPI
from .routers import v1, v2
app = FastAPI(title="API de Dados - Exemplo")
app.include_router(v1.router, prefix="/v1", tags=["v1"])
app.include_router(v2.router, prefix="/v2", tags=["v2"])
# routers/v1.py
from fastapi import APIRouter
router = APIRouter()
@router.get("/items")
def list_items():
# resposta simples v1
return {"version": "v1", "items": ["a", "b"]}
# routers/v2.py
from fastapi import APIRouter
router = APIRouter()
@router.get("/items")
def list_items():
# resposta diferente em v2 (exemplo: items com id)
return {"version": "v2", "items": [{"id":1, "name":"a"}, {"id":2, "name":"b"}]}
Passo 3: negociação de versão via header (header versioning)
Algumas equipas preferem negociar a versão com um cabeçalho para manter URLs estáveis. Aqui mostramos um middleware simples que rerouteia para o router adequado usando um cabeçalho personalizado Accept-Version.
# app/version_middleware.py
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi import Request
from fastapi.responses import JSONResponse
class VersionRoutingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
version = request.headers.get("Accept-Version")
# se existir cabeçalho, prefixa a path com /v{n}
if version and not request.url.path.startswith(f"/v{version}"):
# reescreve o scope para simular um pedido a /v{version}/...
new_path = f"/v{version}{request.url.path}"
request.scope["path"] = new_path
request.scope["raw_path"] = new_path.encode()
return await call_next(request)
# registar no main.py
from .version_middleware import VersionRoutingMiddleware
app.add_middleware(VersionRoutingMiddleware)
Passo 4: documentar diferenças com OpenAPI e metadata
FastAPI gera OpenAPI automaticamente. Use description, tags e operationId para clarificar diferenças entre versões e acrescentar deprecated quando necessário.
# exemplo de endpoint com deprecação
@router.get("/items", deprecated=True, summary="Listar items (v1 - obsoleto)")
def list_items():
return {"version": "v1", "items": []}
# no FastAPI, a documentação está em /docs (Swagger UI) e /redoc
Passo 5: estratégias para compatibilidade e migração
Defina regras internas: o que é breaking change? Alterações ao contract (campos, tipos) são breaking. Para minimizar impacto:
- Prefira adicionar campos em vez de remover
- Marque endpoints obsoletos com deprecated e mantenha-os durante um período
- Documente claramente no OpenAPI e nos changelogs as diferenças
- Se necessário, ofereça um cabeçalho informativo (ex.: X-Deprecation-Date) para avisar clientes
Verificar o resultado
Inicie a aplicação com Uvicorn e teste os dois tipos de versioning.
uvicorn app.main:app --reload
# path versioning
curl http://127.0.0.1:8000/v1/items
curl http://127.0.0.1:8000/v2/items
# header versioning (aplicando middleware)
curl -H "Accept-Version: 2" http://127.0.0.1:8000/items
# abrir documentação
# https://127.0.0.1:8000/docs (Swagger UI)
Verifique que o output difere conforme a versão e que /docs mostra tags separadas para v1 e v2. Teste a deprecação observando o campo deprecated nos endpoints.
Conclusão
Versionar uma API de Dados com FastAPI e OpenAPI permite gerir alterações de forma controlada: use path versioning para clareza e header versioning para URLs estáveis, documente no OpenAPI e marque endpoints obsoletos. Próximo passo: acrescentar testes automatizados que validem compatibilidade entre versões (contract tests). Dica: comece por definir uma política de versionamento (semver ou apenas major) antes de publicar a primeira versão.