FastAPI: O que É e Como Funciona | Python Brasil
Guia completo do FastAPI: framework Python para APIs de alta performance com validação automática, async nativo, JWT e deploy com uvicorn.
O que é FastAPI?
O FastAPI é um framework web moderno e de alta performance para construir APIs com Python. Criado por Sebastián Ramírez e lançado em 2018, ele se baseia em type hints do Python e no Pydantic para oferecer validação automática de dados, documentação interativa e desempenho comparável ao Node.js e Go.
O FastAPI se tornou um dos projetos Python de crescimento mais rápido da história, sendo adotado por empresas como Microsoft, Uber, Netflix e Mercado Livre.
Como Funciona: Starlette + Pydantic
O FastAPI é construído sobre duas fundações:
- Starlette: framework ASGI assíncrono que cuida do roteamento, middlewares, WebSockets e requisições HTTP. É extremamente rápido e leve.
- Pydantic: biblioteca de validação de dados que garante que os dados recebidos e enviados estejam no formato correto, com mensagens de erro claras e automáticas.
Essa combinação permite que o FastAPI seja ao mesmo tempo rápido (Starlette + ASGI), seguro (Pydantic + type hints) e produtivo (documentação automática + autocompletar no editor).
Exemplo Básico
from fastapi import FastAPI, HTTPException, status
from pydantic import BaseModel
from typing import Optional
app = FastAPI(title="Minha API", version="1.0.0")
class Produto(BaseModel):
nome: str
preco: float
em_estoque: bool = True
descricao: Optional[str] = None
# Banco em memória para o exemplo
produtos: dict[int, Produto] = {}
proximo_id = 1
@app.get("/")
async def raiz():
return {"mensagem": "Bem-vindo à API!"}
@app.get("/produtos", response_model=list[Produto])
async def listar_produtos():
return list(produtos.values())
@app.get("/produtos/{produto_id}", response_model=Produto)
async def buscar_produto(produto_id: int):
if produto_id not in produtos:
raise HTTPException(status_code=404, detail="Produto não encontrado")
return produtos[produto_id]
@app.post("/produtos", response_model=Produto, status_code=status.HTTP_201_CREATED)
async def criar_produto(produto: Produto):
global proximo_id
produtos[proximo_id] = produto
proximo_id += 1
return produto
@app.delete("/produtos/{produto_id}", status_code=status.HTTP_204_NO_CONTENT)
async def deletar_produto(produto_id: int):
if produto_id not in produtos:
raise HTTPException(status_code=404, detail="Produto não encontrado")
del produtos[produto_id]
Sistema de Injeção de Dependências
O sistema de dependency injection do FastAPI é um de seus recursos mais poderosos. Permite reutilizar lógica como autenticação, sessões de banco de dados e paginação de forma limpa.
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy.orm import Session
from typing import Generator
app = FastAPI()
# Dependência de banco de dados
def get_db() -> Generator:
db = SessionLocal()
try:
yield db
finally:
db.close()
# Dependência de paginação reutilizável
class Paginacao:
def __init__(self, pagina: int = 1, tamanho: int = 20):
self.offset = (pagina - 1) * tamanho
self.limit = tamanho
# Dependência de autenticação
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/token")
async def usuario_atual(token: str = Depends(oauth2_scheme)):
# Valida o token e retorna o usuário
usuario = verificar_token(token)
if not usuario:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Token inválido",
headers={"WWW-Authenticate": "Bearer"},
)
return usuario
@app.get("/produtos")
async def listar_produtos(
paginacao: Paginacao = Depends(),
db: Session = Depends(get_db),
usuario = Depends(usuario_atual),
):
return db.query(Produto).offset(paginacao.offset).limit(paginacao.limit).all()
Autenticação com JWT
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta
SECRET_KEY = "sua-chave-secreta"
ALGORITHM = "HS256"
EXPIRACAO_TOKEN = 30 # minutos
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/token")
def criar_token(dados: dict) -> str:
payload = dados.copy()
payload["exp"] = datetime.utcnow() + timedelta(minutes=EXPIRACAO_TOKEN)
return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)
@app.post("/auth/token")
async def login(form: OAuth2PasswordRequestForm = Depends()):
usuario = autenticar_usuario(form.username, form.password)
if not usuario:
raise HTTPException(status_code=400, detail="Credenciais inválidas")
token = criar_token({"sub": usuario.email})
return {"access_token": token, "token_type": "bearer"}
Tarefas em Background
O FastAPI permite executar tarefas em background sem bloquear a resposta:
from fastapi import FastAPI, BackgroundTasks
import smtplib
app = FastAPI()
def enviar_email_boas_vindas(email: str, nome: str):
# Função executada em segundo plano
print(f"Enviando e-mail de boas-vindas para {nome} ({email})")
# ... lógica de envio de e-mail
@app.post("/usuarios", status_code=201)
async def criar_usuario(usuario: UsuarioCreate, background_tasks: BackgroundTasks):
novo_usuario = salvar_usuario(usuario)
background_tasks.add_task(
enviar_email_boas_vindas,
email=usuario.email,
nome=usuario.nome
)
return novo_usuario
Middleware e CORS
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
import time
app = FastAPI()
# CORS para frontends
app.add_middleware(
CORSMiddleware,
allow_origins=["https://meusite.com.br", "http://localhost:3000"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Middleware customizado
@app.middleware("http")
async def adicionar_tempo_resposta(request, call_next):
inicio = time.time()
response = await call_next(request)
duracao = time.time() - inicio
response.headers["X-Process-Time"] = str(duracao)
return response
Integração com Banco de Dados (SQLAlchemy Assíncrono)
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from fastapi import Depends
DATABASE_URL = "postgresql+asyncpg://user:pass@localhost/dbname"
engine = create_async_engine(DATABASE_URL)
class Base(DeclarativeBase):
pass
class Produto(Base):
__tablename__ = "produtos"
id: Mapped[int] = mapped_column(primary_key=True)
nome: Mapped[str] = mapped_column(nullable=False)
preco: Mapped[float]
async def get_session() -> AsyncSession:
async with AsyncSession(engine) as session:
yield session
@app.get("/produtos/{produto_id}")
async def buscar_produto(produto_id: int, db: AsyncSession = Depends(get_session)):
produto = await db.get(Produto, produto_id)
if not produto:
raise HTTPException(status_code=404, detail="Não encontrado")
return produto
Testando com TestClient
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_listar_produtos():
resposta = client.get("/produtos")
assert resposta.status_code == 200
assert isinstance(resposta.json(), list)
def test_criar_produto():
resposta = client.post("/produtos", json={
"nome": "Notebook",
"preco": 4999.90,
"em_estoque": True
})
assert resposta.status_code == 201
assert resposta.json()["nome"] == "Notebook"
def test_produto_nao_encontrado():
resposta = client.get("/produtos/99999")
assert resposta.status_code == 404
Deploy com Uvicorn e Gunicorn
# Desenvolvimento
uvicorn main:app --reload --port 8000
# Produção com múltiplos workers
gunicorn main:app \
--workers 4 \
--worker-class uvicorn.workers.UvicornWorker \
--bind 0.0.0.0:8000
# Docker
# Dockerfile
# FROM python:3.12-slim
# WORKDIR /app
# COPY requirements.txt .
# RUN pip install -r requirements.txt
# COPY . .
# CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Performance
O FastAPI é um dos frameworks Python mais rápidos disponíveis. Benchmarks independentes mostram performance comparável a Node.js e Go em cenários de I/O intensivo, graças ao modelo assíncrono baseado em ASGI e ao processamento eficiente do Pydantic v2 (escrito em Rust).
Erros Comuns
- Misturar funções sync e async: funções
defcomuns bloqueiam o event loop; useasync defpara operações de I/O - Não usar
response_model: sem ele, dados sensíveis podem vazar na resposta - Dependências com estado global: evite variáveis globais mutáveis; prefira dependências injetadas
- Esquecer validação de entrada: confie no Pydantic para validar dados antes de processar
Boas Práticas
- Organize o projeto em routers separados por domínio
- Use
response_modelem todas as rotas para controlar o que é retornado - Documente parâmetros com
Query,PatheBodydo FastAPI - Use variáveis de ambiente com
pydantic-settingspara configuração - Escreva testes com
TestClientantes de subir para produção
Termos Relacionados
- Pydantic - Validação de dados usada pelo FastAPI
- Async/Await - Programação assíncrona em Python
- Type Hints - Tipagem estática que potencializa o FastAPI
- API REST - Padrão de APIs RESTful