Introdução ao FastAPI — Por Que É o Framework Web Python de Próxima Geração
Se Flask é um canivete suíço versátil e Django é um SUV totalmente equipado, então FastAPI é um supercarro elétrico—acelera rapidamente, é eficiente e vem com um painel gerado automaticamente.
1. O Que Você Vai Aprender
- A Diferença Fundamental Entre ASGI e WSGI: Por Que Assíncrono É o Futuro
- FastAPI vs. Flask vs. Django REST Framework: Comparação de Desempenho e Experiência de Desenvolvimento
- Como Type Hints Impulsionam Validação Automática e Geração de Documentação
- Uma Análise Profunda da Arquitetura Subjacente do Starlette e Pydantic
- Visão Geral do Projeto PriceTracker: O Que Alice Está Planejando Construir
2. A História Real da Alice
(1) Problema: O framework síncrono não consegue lidar com milhões de requisições
Alice é uma engenheira de backend construindo o PriceTracker—uma API SaaS de rastreamento de preços para uma plataforma de e-commerce—que precisa lidar com consultas em tempo real para milhões de preços de produtos. Ela inicialmente construiu um protótipo usando Flask, mas quando as requisições concorrentes excederam 1.000 QPS, o modelo síncrono WSGI fez com que cada requisição ficasse enfileirada, e a latência P99 disparou para 3.000 ms. Bob (engenheiro frontend) reclamou do carregamento lento da página, e Charlie (DevOps) disse que o custo da escalabilidade horizontal era muito alto.
(2) A Solução FastAPI
O FastAPI é baseado no protocolo assíncrono ASGI e pode lidar com milhares de conexões concorrentes com um único processo. Type hints geram automaticamente a documentação OpenAPI e validam os dados da requisição, então Alice não precisa escrever código de validação ou documentação manualmente.
from fastapi import FastAPI
app = FastAPI()
@app.get("/products/{product_id}")
async def get_product(product_id: int):
# Type hint valida automaticamente e gera documentação
return {"product_id": product_id, "name": "Widget"}
(3) Resultado
Após migrar para o FastAPI, o QPS de nó único do PriceTracker aumentou de 500 para mais de 4.000, a latência P99 caiu para 50 ms, a página frontend do Bob carregou 5 vezes mais rápido, e os custos de servidor do Charlie foram reduzidos em 60%.
3. ASGI e WSGI: Assíncrono É o Futuro
(1) Gargalos de Sincronização WSGI
WSGI (Web Server Gateway Interface) é o padrão tradicional para aplicações web Python; cada requisição ocupa uma thread, e a thread bloqueia e aguarda quando ocorre uma operação de I/O (como uma consulta ao banco de dados ou requisição de rede).
flowchart LR
Client1[Cliente 1] -->|Requisição| WSGI[Servidor WSGI]
Client2[Cliente 2] -->|Requisição| WSGI
Client3[Cliente 3] -->|Requisição| WSGI
WSGI -->|Thread 1| DB1[(Banco de Dados)]
WSGI -->|Thread 2| DB1
WSGI -->|Thread 3 - BLOQUEADA| DB1
| Dimensão | WSGI | ASGI |
|---|---|---|
| Modelo de Conexão | Uma Requisição, Uma Thread | Corrotinas Assíncronas, Single-Thread com Múltiplas Conexões |
| Limite de Concorrência | Limitado pelo pool de threads (tipicamente 10-100) | Virtualmente ilimitado (corrotinas são leves) |
| Espera de I/O | Bloqueia a Thread | Não bloqueante, alterna para outra corrotina |
| WebSocket | Não suportado | Suporte nativo |
| Servidores Típicos | Gunicorn + Flask | Uvicorn + FastAPI |
(2) As Vantagens Assíncronas do ASGI
ASGI (Asynchronous Server Gateway Interface) é uma extensão assíncrona do WSGI que suporta a sintaxe async/await, permitindo que um único processo lidar com milhares de conexões concorrentes.
import asyncio
import time
# Estilo WSGI - bloqueia a thread
def sync_handler():
time.sleep(1) # Thread bloqueada por 1 segundo
return "done"
# Estilo ASGI - não bloqueante
async def async_handler():
await asyncio.sleep(1) # Event loop alterna para outras tarefas
return "done"
(1) ▶ Exemplo: Comparação de Concorrência Síncrona vs. Assíncrona
import asyncio
import time
async def fetch_price(product_id: int) -> dict:
# Simular latência de I/O do banco de dados
await asyncio.sleep(0.1)
return {"product_id": product_id, "price": 9.99}
async def main():
start = time.perf_counter()
# 100 requisições concorrentes - assíncrono termina em ~0.1s
results = await asyncio.gather(*[fetch_price(i) for i in range(100)])
elapsed = time.perf_counter() - start
print(f"Async: {len(results)} itens em {elapsed:.2f}s")
asyncio.run(main())
Saída:
Execução Bem-Sucedida
Saída:
Async: 100 itens em 0.10s
4. FastAPI vs. Flask vs. Django DRF
(1) Posicionamento no Ecossistema de Frameworks
flowchart LR
FastAPI[FastAPI] --> Starlette[Starlette ASGI]
Starlette --> Uvicorn[Servidor Uvicorn]
Uvicorn --> ASGI_Protocol[Protocolo ASGI]
FastAPI --> Pydantic[Pydantic V2]
Flask2[Flask] --> Werkzeug[Werkzeug WSGI]
Werkzeug --> Gunicorn[Gunicorn]
Django2[Django DRF] --> Django_Core[Django Core]
| Dimensão | FastAPI | Flask | Django DRF |
|---|---|---|---|
| Desempenho (TechEmpower RPS) | ~40.000 | ~1.200 | ~800 |
| Suporte Assíncrono | async/await nativo | Requer extensão | Suporte limitado |
| Documentação Automática | Auto-Geração OpenAPI | Requer Flask-RESTX | Requer drf-spectacular |
| Validação de Tipos | Validação Automática Pydantic | Validação Manual | Definição Manual de Serializer |
| Curva de Aprendizado | Baixa (Type hints servem como documentação) | Baixa | Alta |
| Escala do Projeto | Serviços API de Pequeno a Médio Porte | Serviços Pequenos | Projetos Full-Stack Grandes |
(2) Por Que FastAPI É Mais Adequado para o PriceTracker
| Requisitos do PriceTracker | Vantagens do FastAPI | Desvantagens do Flask |
|---|---|---|
| Milhões de consultas por segundo (QPS) | Alta concorrência com corrotinas assíncronas | Baixa concorrência com bloqueio síncrono |
| Feeds de preços em tempo real via WebSocket | Suporte nativo | Não suportado |
| Documentação Automática da API para Bob | Auto-Geração OpenAPI | Requer Configuração Adicional |
| Validação de Dados da Requisição | Pydantic Automática | Decorador de Validação Personalizado |
| Autenticação JWT | Ferramentas OAuth2 Integradas | Requer Bibliotecas de Terceiros |
(1) ▶ Exemplo: Comparação de Três Formas de Escrever a Mesma API
# === FastAPI: Type hints = validação automática + documentação ===
from fastapi import FastAPI
from pydantic import BaseModel
class Product(BaseModel):
name: str
price: float
app = FastAPI()
@app.post("/products")
async def create_product(product: Product):
return product # Auto validado, auto documentado
Saída:
# Função definida com sucesso
# === Flask: Validação manual, sem documentação automática ===
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/products", methods=["POST"])
def create_product():
data = request.get_json()
if not data or "name" not in data or "price" not in data:
return jsonify({"error": "Invalid data"}), 400
if not isinstance(data["price"], (int, float)):
return jsonify({"error": "Price must be number"}), 400
return jsonify(data)
5. Type Hints Impulsionam Tudo
(1) O Valor Triplo dos Type Hints
O FastAPI usa type hints do Python para realizar três coisas de uma vez: validação de dados, serialização/desserialização e geração de documentação OpenAPI.
| Type Hinting | Frameworks Tradicionais | FastAPI |
|---|---|---|
| Validação de Dados | if/else escrito manualmente | Pydantic Automático |
| Serialização JSON | json.dumps manual |
model_dump() Automático |
| Documentação da API | YAML Swagger escrito manualmente | Auto-Geração OpenAPI |
| Auto-Complete do IDE | Nenhum | Inferência Completa de Tipos |
(1) ▶ Exemplo: Validação Automática de Type Hint
from fastapi import FastAPI, Query
from typing import Optional
app = FastAPI()
@app.get("/prices")
async def search_prices(
min_price: float = Query(0.0, ge=0, description="Preço mínimo em USD"),
max_price: float = Query(999999.0, le=999999, description="Preço máximo em USD"),
category: Optional[str] = Query(None, max_length=50),
):
return {"min_price": min_price, "max_price": max_price, "category": category}
Saída:
# Função definida com sucesso
(2) ▶ Exemplo: Documentação OpenAPI Gerada Automaticamente
# Após definir o endpoint acima, visite:
# http://localhost:8000/docs -> Swagger UI
# http://localhost:8000/redoc -> ReDoc
# http://localhost:8000/openapi.json -> Schema OpenAPI bruto
Saída (trecho de
/openapi.json):
{
"paths": {
"/prices": {
"get": {
"summary": "Search Prices",
"parameters": [
{"name": "min_price", "in": "query", "schema": {"type": "number", "minimum": 0.0}}
]
}
}
}
}
(2) O Papel do Pydantic
Pydantic V2 é um motor de validação de dados para o FastAPI; seu núcleo foi reescrito em Rust, tornando-o 5 a 50 vezes mais rápido que o V1.
| Recurso | Pydantic V1 | Pydantic V2 |
|---|---|---|
| Motor Central | Python | Rust (pydantic-core) |
| Velocidade de Verificação | Referência | 5-50x Mais Rápido |
| Validador | @validator |
@field_validator/@model_validator |
| Configuração | class Config |
model_config = ConfigDict(...) |
| Serialização | .dict() |
.model_dump() |
6. Arquitetura Subjacente: Starlette + Pydantic
(1) Arquitetura de Três Camadas do FastAPI
O FastAPI em si é um wrapper leve; suas capacidades centrais vêm do Starlette (um framework ASGI) e do Pydantic (validação de dados).
| Nível | Componente | Responsabilidades |
|---|---|---|
| Camada de Aplicação | FastAPI | Registro de Rotas, Injeção de Dependência, Geração OpenAPI |
| Camada ASGI | Starlette | Middleware, Tratamento de Requisição/Resposta, WebSocket |
| Camada de Validação | Pydantic | Validação de dados, serialização e conversão de tipos |
| Camada de Serviço | Uvicorn | Servidor ASGI, Gerenciamento do Event Loop |
(1) ▶ Exemplo: Usando Recursos do Starlette Diretamente no FastAPI
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware
from starlette.responses import JSONResponse
app = FastAPI()
# Middleware Starlette funciona perfeitamente com FastAPI
app.add_middleware(CORSMiddleware, allow_origins=["*"])
# Classes de resposta Starlette também funcionam
@app.get("/health")
async def health_check():
return JSONResponse({"status": "healthy"})
Saída:
# Função definida com sucesso
(2) ▶ Exemplo: Usando Modelos Pydantic no FastAPI
from fastapi import FastAPI
from pydantic import BaseModel, Field
class PriceCreate(BaseModel):
product_id: int = Field(gt=0)
price: float = Field(gt=0, description="Preço em USD")
currency: str = Field(default="USD", max_length=3)
app = FastAPI()
@app.post("/prices")
async def create_price(data: PriceCreate):
# dados já validados e parseados pelo Pydantic
validated = data.model_dump()
return {"status": "created", "data": validated}
Saída:
# Função definida com sucesso
7. Visão Geral do Projeto PriceTracker
(1) O que Alice está tentando construir?
O PriceTracker é uma API SaaS de rastreamento de preços. Suas funcionalidades principais incluem:
| Módulo de Funcionalidade | Endpoint da API | Descrição |
|---|---|---|
| Gerenciamento de Produtos | /products CRUD |
Milhões de Registros de Produtos |
| Rastreamento de Preços | /prices CRUD |
Consultas e Notificações de Preços em Tempo Real |
| Autenticação de Usuários | /auth/login, /auth/register |
Autenticação JWT de Token Duplo |
| Planos de Assinatura | Free/Pro/Enterprise | Permissões Multi-Tenant SaaS |
| Importação em Lote | /import/csv |
Importação Assíncrona de Arquivos CSV de 1.000 Linhas |
| Notificações Push em Tempo Real | WebSocket /ws/prices |
Alertas Instantâneos de Mudança de Preço |
flowchart LR
Bob[Bob - Frontend] -->|HTTP/WebSocket| API[PriceTracker API]
Charlie[Charlie - DevOps] -->|Monitorar| API
API -->|Consultar| DB[(PostgreSQL)]
API -->|Cache| Redis[(Redis)]
API -->|Tarefa| Celery[Celery Worker]
Celery -->|Scrape| External[Sites Externos]
(1) ▶ Exemplo: PriceTracker—Versão Mínima Funcional
from fastapi import FastAPI
from pydantic import BaseModel, Field
from typing import Optional
app = FastAPI(title="PriceTracker API", version="0.1.0")
class ProductCreate(BaseModel):
name: str = Field(max_length=200)
category: str = Field(max_length=100)
base_price: float = Field(gt=0, description="Preço base em USD")
class ProductResponse(BaseModel):
id: int
name: str
category: str
base_price: float
PRODUCTS_DB: dict[int, dict] = {}
_counter = 0
@app.post("/products", response_model=ProductResponse)
async def create_product(product: ProductCreate):
global _counter
_counter += 1
record = {"id": _counter, **product.model_dump()}
PRODUCTS_DB[_counter] = record
return record
@app.get("/products/{product_id}", response_model=ProductResponse)
async def get_product(product_id: int):
if product_id not in PRODUCTS_DB:
from fastapi import HTTPException
raise HTTPException(status_code=404, detail="Product not found")
return PRODUCTS_DB[product_id]
Saída:
# Função definida com sucesso
8. Exemplo Abrangente
A força central do FastAPI reside na validação automática e geração de documentação orientada por type hints. O exemplo a seguir demonstra um endpoint completo de consulta de preços que integra parâmetros de caminho, modelos Pydantic e modelos de resposta.
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI(title="PriceTracker Demo")
class PriceResponse(BaseModel):
product_id: int = Field(gt=0)
product_name: str
price: float = Field(gt=0)
currency: str = "USD"
PRICES_DB: dict[int, dict] = {
1: {"product_id": 1, "product_name": "Widget", "price": 9.99},
2: {"product_id": 2, "product_name": "Gadget", "price": 24.50},
}
@app.get("/products/{product_id}", response_model=PriceResponse)
async def get_price(product_id: int):
if product_id not in PRICES_DB:
from fastapi import HTTPException
raise HTTPException(status_code=404, detail="Product not found")
return PRICES_DB[product_id]
Saída:
GET /products/1 → {"product_id":1,"product_name":"Widget","price":9.99,"currency":"USD"}
GET /products/99 → 404 Not Found
❓ Perguntas Frequentes
async/await?async oferece melhor desempenho em cenários intensivos de I/O (como requisições de banco de dados e rede).📖 Resumo
- O FastAPI é baseado no protocolo assíncrono ASGI; um único processo pode lidar com milhares de requisições concorrentes, entregando desempenho muito superior aos frameworks WSGI.
- Type hints impulsionam simultaneamente validação de dados, serialização e geração de documentação OpenAPI, reduzindo código boilerplate em 70%
- O FastAPI é um wrapper leve sobre Starlette (framework ASGI) e Pydantic (validação de dados), e cada camada pode ser usada independentemente.
- O Pydantic V2 reescreveu seu núcleo em Rust, tornando-o 5 a 50 vezes mais rápido que o V1, e é chave para o desempenho do FastAPI
- O projeto PriceTracker abrange 25 aulas, levando você da construção do zero ao deploy em produção, cobrindo cenários SaaS com milhões de usuários.
📝 Exercícios
- Exercício Básico (Dificuldade: ⭐): Instale FastAPI e Uvicorn, crie um endpoint GET que retorna
{"message": "Hello PriceTracker"}, e inicie-o usandouvicorn. Dica:pip install fastapi uvicorn - Problema Avançado (Dificuldade ⭐⭐): Adicione o parâmetro de caminho
nameao endpoint, retorne{"message": "Hello, {name}"}, e visite/docsno seu navegador para visualizar a documentação gerada automaticamente. Dica:@app.get("/hello/{name}") - Desafio (Dificuldade: ⭐⭐⭐): Crie um modelo Pydantic
PriceInputque incluiproduct_name: streprice: float(deve ser > 0), usa um endpoint POST para receber dados, e retorna o resultado validado. Dica: Herde deBaseModele useField(gt=0)
---|



