Documentação de API e Personalização OpenAPI — Criando Documentação de API Profissional
A documentação de API é como um manual de produto — sem ela, os clientes (desenvolvedores) não usarão seu produto; se for mal escrita, os clientes votarão com os pés. A geração automática de documentação é a arma secreta do FastAPI, mas a configuração padrão é apenas o ponto de partida; a personalização é o que diferencia os profissionais.
1. O Que Você Vai Aprender
- Configuração do Swagger UI e ReDoc:
swagger_ui_parameters, JS/CSS Personalizado - Personalização do Schema OpenAPI:
openapi_route,generate_unique_id_functionpersonalizado - Melhores Práticas para
description/summary/tags/deprecated - Valores de exemplo e templates de resposta:
OpenApiResponse+json_schema_extra - Cenário Alice: Documentação de API SaaS Profissional do PriceTracker
2. A História Real da Alice
(1) Problema: A documentação padrão não é profissional o suficiente
A documentação da API do PriceTracker da Alice usa o Swagger UI padrão do FastAPI, onde todos os endpoints estão misturados sem agrupamento, então Bob não consegue encontrar o endpoint que precisa. Para piorar, a documentação não possui exemplos de requisição, então Bob não sabe qual valor inserir no campo currency; não há versionamento para corpos de requisição ou resposta; e endpoints novos e obsoletos estão todos misturados.
(2) Soluções Personalizadas para OpenAPI
O FastAPI permite personalização profunda da documentação OpenAPI — incluindo agrupamento por tags, valores de exemplo, marcadores de obsolescência e schemas personalizados — transformando a documentação da API de apenas "legível" para "utilizável."
(3) Resultado
Bob pode simplesmente abrir a documentação para localizar rapidamente endpoints por tag (Products/Prices/Auth). Valores de exemplo eliminam a necessidade de adivinhar ao fazer requisições, e endpoints obsoletos são marcados em cinza para evitar uso acidental. Como resultado, a qualidade da documentação foi elevada do nível de "referência interna" para "lançamento público."
3. Configuração do Swagger UI e ReDoc
(1) Processo de Geração OpenAPI
flowchart LR
A[FastAPI Routes] --> B[Pydantic Models]
B --> C[OpenAPI 3.1 Schema]
C --> D[Swagger UI /docs]
C --> E[ReDoc /redoc]
C --> F[Raw JSON /openapi.json]
(1) ▶Exemplo: Configuração de Documentação em Nível de Aplicação FastAPI
from fastapi import FastAPI
app = FastAPI(
title="PriceTracker API",
description="""
## PriceTracker SaaS API
Serviço de rastreamento de preços de e-commerce para monitoramento de preços em nível de milhões de produtos.
### (1) Autenticação
Todos os endpoints protegidos exigem um token Bearer obtido em `/auth/login`.
### (2) Limites de Taxa
- Free: 100 requisições/min
- Pro: 1000 requisições/min
- Enterprise: ilimitado
""",
version="1.0.0",
terms_of_service="https://pricetracker.example.com/terms",
contact={
"name": "PriceTracker Support",
"url": "https://pricetracker.example.com/support",
"email": "support@pricetracker.example.com",
},
license_info={
"name": "MIT License",
"url": "https://opensource.org/licenses/MIT",
},
docs_url="/docs",
redoc_url="/redoc",
openapi_url="/openapi.json",
)
Saída:
# Execução Bem-sucedida
(3) ▶Exemplo: Personalizando Parâmetros do Swagger UI
app = FastAPI(
swagger_ui_parameters={
"persistAuthorization": True, # Manter autenticação entre refreshes de página
"displayRequestDuration": True, # Mostrar duração da requisição
"filter": True, # Habilitar filtro de busca
"syntaxHighlight.theme": "monokai", # Tema de destaque de código
"defaultModelsExpandDepth": 1, # Expandir modelos 1 nível de profundidade
"defaultModelExpandDepth": 1,
}
)
Saída:
# Execução Bem-sucedida
| Parâmetro | Padrão | Descrição |
|---|---|---|
persistAuthorization |
False | Manter autenticação ao atualizar a página |
displayRequestDuration |
False | Mostrar duração da requisição |
filter |
False | Habilitar Filtro de Busca |
defaultModelsExpandDepth |
1 | Profundidade de Expansão do Modelo |
syntaxHighlight.theme |
"agate" | Tema de Destaque de Código |
4. Agrupamento por Tags e Marcadores de Obsolescência
(1) Tags: Endpoints Agrupados
(1) ▶Exemplo: Definindo Tags
from fastapi import FastAPI, APIRouter
tags_metadata = [
{
"name": "auth",
"description": "Operações de autenticação. Login, registro, renovação de token.",
},
{
"name": "products",
"description": "Gerenciamento de produtos. Operações CRUD para produtos rastreados.",
},
{
"name": "prices",
"description": "Dados de preço. Consultar, importar e rastrear mudanças de preço.",
},
{
"name": "admin",
"description": "Operações administrativas. Requer papel de admin.",
},
]
app = FastAPI(
title="PriceTracker API",
openapi_tags=tags_metadata,
)
Saída:
# Execução Bem-sucedida
(2) ▶Exemplo: Atribuição de Tags a Endpoints
@app.post("/auth/login", tags=["auth"])
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
...
@app.get("/api/v1/products", tags=["products"])
async def list_products():
...
@app.post("/api/v1/prices", tags=["prices"])
async def create_price():
...
@app.get("/api/v1/admin/stats", tags=["admin"])
async def admin_stats():
...
Saída:
# Função definida com sucesso
(3) ▶Exemplo: Marcando um endpoint como obsoleto
@app.get(
"/api/v1/products/{product_id}/history",
tags=["prices"],
deprecated=True,
summary="[DEPRECATED] Use GET /prices?product_id={id} em vez disso",
)
async def get_price_history_deprecated(product_id: int):
"""Este endpoint está obsoleto. Use o endpoint prices com filtro product_id."""
...
Saída:
# Função definida com sucesso
5. Valores de Exemplo e Templates de Resposta
(1) json_schema_extra e examples
(1) ▶Exemplo: Valores de exemplo para modelos Pydantic
from pydantic import BaseModel, Field
class ProductCreate(BaseModel):
name: str = Field(
min_length=1, max_length=200,
description="Nome de exibição do produto",
examples=["Mouse Sem Fio", "Hub USB-C", "Teclado Mecânico"],
)
category: str = Field(
max_length=100,
description="Categoria do produto",
examples=["eletrônicos", "roupas", "alimentos"],
)
base_price: float = Field(
gt=0,
description="Preço base em USD",
examples=[9.99, 49.99, 199.99],
)
model_config = {
"json_schema_extra": {
"examples": [
{
"name": "Mouse Sem Fio",
"category": "eletrônicos",
"base_price": 29.99,
}
]
}
}
Saída:
# Execução Bem-sucedida
(2) ▶Exemplo: Exemplo de resposta em nível de endpoint
from fastapi import FastAPI
from fastapi.responses import JSONResponse
@app.post(
"/api/v1/products",
response_model=ProductResponse,
status_code=201,
summary="Criar um novo produto",
description="Criar um novo produto no banco de dados do PriceTracker.",
responses={
201: {
"description": "Produto criado com sucesso",
"content": {
"application/json": {
"example": {
"id": 1,
"name": "Mouse Sem Fio",
"category": "eletrônicos",
"base_price": 29.99,
}
}
},
},
401: {"description": "Autenticação necessária"},
403: {"description": "Permissões insuficientes"},
422: {"description": "Erro de validação"},
},
)
async def create_product(product: ProductCreate):
...
Saída:
# Função definida com sucesso
6. Schema OpenAPI Personalizado
(1) generate_unique_id_function
(1) ▶Exemplo: Gerando um ID de Endpoint Personalizado
from fastapi import FastAPI
def custom_generate_unique_id(route):
# Formato: {method}_{tag}_{path}
tags = route.tags or ["default"]
tag = tags[0]
method = route.methods.pop() if route.methods else "GET"
path = route.path.replace("/", "_").strip("_").replace("{", "").replace("}", "")
return f"{method}_{tag}_{path}"
app = FastAPI(
generate_unique_id_function=custom_generate_unique_id,
)
Saída:
# Função definida com sucesso
(2) Comparação de Melhores Práticas de Documentação
| Dimensão | Padrão | Melhor Prática |
|---|---|---|
| Grupos de Endpoints | Nenhum | Tags por Função |
| Endpoints abandonados | Misturados com endpoints normais | deprecated=True marca cinza |
| Exemplo de Requisição | Nenhum | examples + json_schema_extra |
| Templates de Resposta | Apenas 200 | Cobertura Completa para 201/401/403/422 |
| Descrição | Nome de Função Simples | Summary + Description |
| Informação de Certificação | Nenhuma | Página Inicial da Documentação: Explicação de Métodos de Certificação |
| Versionamento | Versão Única | Versionamento por Path de URL /api/v1/ |
❓Perguntas Frequentes
include_in_schema=False: @app.get("/internal", include_in_schema=False). Isso é adequado para health checks internos e endpoints de monitoramento.openapi personalizada.swagger_ui_parameters para fornecer uma URL de CSS, ou use get_swagger_ui_html para personalizar completamente o HTML.APIRouter(prefix="/api/v1") separado para cada versão e distinga as versões usando tags. Alternativamente, crie um sub-aplicativo FastAPI separado para cada versão.📖Resumo
- O FastAPI gera automaticamente documentação OpenAPI 3.1; o Swagger UI fornece testes interativos; o ReDoc oferece uma experiência de leitura visualmente atraente
openapi_tagsAgrupa endpoints por função;deprecated=TrueMarca endpoints obsoletosField(examples=[...])ejson_schema_extraadicionam valores de exemplo ao modeloresponses={status: {description, content}}Define templates de resposta de múltiplos códigos de status para endpoints- Personalize
generate_unique_id_functionpara controlar o formato de nomenclatura dos IDs de operação OpenAPI
📝Exercícios
- Questão Básica (Dificuldade ⭐): Configure a documentação em nível de aplicação FastAPI para o PriceTracker — incluindo título, descrição, número de versão e informações de contato — e adicione
persistAuthorization=Truepara garantir que o Swagger UI retenha o status de autenticação. Dica:FastAPI(title=..., swagger_ui_parameters={...}) - Exercício Avançado (Dificuldade ⭐⭐): Defina 4 tags (auth/products/prices/admin), atribua a tag correta a cada endpoint, marque o endpoint obsoleto com
deprecated=True, e verifique se os endpoints estão agrupados por tag no Swagger UI. Dica:openapi_tags=[...]+tags=["products"] - Desafio (Dificuldade ⭐⭐⭐): Adicione um exemplo completo de
json_schema_extraao ProductCreate, e adicione templates de resposta para os códigos de status 201, 401, 403 e 422 (incluindo conteúdo de exemplo) ao endpoint POST /products para implementar agenerate_unique_id_functionpersonalizada. Dica:responses={201: {"content": {...}}}+generate_unique_id_function
---|



