O FastAPI é uma das ferramentas mais populares para criar APIs em Python. Ele combina simplicidade, velocidade e recursos modernos que facilitam o desenvolvimento de aplicações web robustas.
Se você já trabalha com Python e quer criar APIs de forma eficiente, este guia completo vai te ensinar tudo que precisa saber sobre FastAPI.
O Que É FastAPI e Por Que Escolhê-lo
FastAPI é um framework web moderno para criar APIs em Python. Foi desenvolvido por Sebastian Ramirez e lançado em 2018. Desde então, ganhou popularidade rapidamente entre desenvolvedores do mundo todo.
O framework se destaca pela sua alta performance. É um dos frameworks Python mais rápidos disponíveis, competindo com frameworks de outras linguagens como Node.js e Go.
Principais Vantagens do FastAPI
O FastAPI oferece várias vantagens que o tornam atrativo:
- Velocidade excepcional: Baseado no Starlette e Pydantic, oferece performance comparável a frameworks de linguagens compiladas
- Documentação automática: Gera documentação interativa automaticamente usando OpenAPI e JSON Schema
- Validação de dados: Valida automaticamente os dados de entrada e saída usando type hints do Python
- Suporte a async: Funciona nativamente com programação assíncrona
- Fácil de aprender: Sintaxe intuitiva para quem já conhece Python
Instalação e Configuração Inicial
Para começar com FastAPI, você precisa instalar o framework e suas dependências.
Preparando o Ambiente
Primeiro, crie um ambiente virtual para seu projeto:
python -m venv fastapi_env
source fastapi_env/bin/activate # No Windows: fastapi_env\Scripts\activate
Instalando o FastAPI
Instale o FastAPI junto com um servidor ASGI como o Uvicorn:
pip install fastapi uvicorn
O Uvicorn é um servidor ASGI que executa aplicações FastAPI em produção e desenvolvimento.
Primeira API com FastAPI
Vamos criar nossa primeira API. Crie um arquivo chamado main.py
:
from fastapi import FastAPI
# Criar uma instância do FastAPI
app = FastAPI()
# Definir uma rota básica
@app.get("/")
def ler_raiz():
return {"mensagem": "Olá, mundo!"}
# Rota com parâmetro
@app.get("/usuarios/{usuario_id}")
def ler_usuario(usuario_id: int):
return {"usuario_id": usuario_id, "nome": f"Usuario {usuario_id}"}
Para executar a aplicação:
uvicorn main:app --reload
Acesse http://127.0.0.1:8000
no seu navegador. Você verá:
{"mensagem": "Olá, mundo!"}
Criando Rotas e Endpoints
As rotas são os caminhos que definem como sua API responde a diferentes requisições. No FastAPI, você define rotas usando decoradores.
Métodos HTTP Principais
O FastAPI suporta todos os métodos HTTP principais:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items") # Para buscar dados
def listar_items():
return {"items": ["item1", "item2", "item3"]}
@app.post("/items") # Para criar novos dados
def criar_item(nome: str):
return {"item_criado": nome}
@app.put("/items/{item_id}") # Para atualizar dados
def atualizar_item(item_id: int, nome: str):
return {"item_id": item_id, "novo_nome": nome}
@app.delete("/items/{item_id}") # Para deletar dados
def deletar_item(item_id: int):
return {"item_deletado": item_id}
Parâmetros de Caminho e Query
Você pode capturar parâmetros diretamente da URL:
@app.get("/produtos/{produto_id}")
def obter_produto(produto_id: int, mostrar_detalhes: bool = False):
produto = {"id": produto_id, "nome": f"Produto {produto_id}"}
if mostrar_detalhes:
produto["preco"] = 99.90
produto["categoria"] = "eletrônicos"
return produto
Exemplo de uso: GET /produtos/123?mostrar_detalhes=true
Resultado:
{
"id": 123,
"nome": "Produto 123",
"preco": 99.90,
"categoria": "eletrônicos"
}
Validação de Dados com Pydantic
O Pydantic é uma biblioteca que o FastAPI usa para validação de dados. Ele garante que os dados recebidos estejam no formato correto.
Criando Modelos de Dados
Defina modelos usando classes que herdam de BaseModel
:
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
class Usuario(BaseModel):
nome: str
email: str
idade: int
ativo: bool = True
class UsuarioResposta(BaseModel):
id: int
nome: str
email: str
@app.post("/usuarios", response_model=UsuarioResposta)
def criar_usuario(usuario: Usuario):
# Simular criação de usuário
novo_usuario = {
"id": 1,
"nome": usuario.nome,
"email": usuario.email
}
return novo_usuario
Validação Automática
O FastAPI valida automaticamente os dados de entrada:
from pydantic import BaseModel, EmailStr, Field
class Produto(BaseModel):
nome: str = Field(..., min_length=1, max_length=100)
preco: float = Field(..., gt=0, description="Preço deve ser maior que zero")
categoria: str
em_estoque: bool = True
@app.post("/produtos")
def criar_produto(produto: Produto):
print(f"Produto criado: {produto.nome}")
return {"status": "criado", "produto": produto}
Se você enviar dados inválidos, o FastAPI retornará automaticamente uma mensagem de erro detalhada.
Documentação Automática
Uma das funcionalidades mais impressionantes do FastAPI é a geração automática de documentação.
Swagger UI
Acesse http://127.0.0.1:8000/docs
para ver a documentação interativa do Swagger UI. Esta interface permite:
- Visualizar todas as rotas disponíveis
- Testar endpoints diretamente no navegador
- Ver exemplos de requisições e respostas
- Baixar especificações da API
ReDoc
Alternativamente, acesse http://127.0.0.1:8000/redoc
para ver a mesma documentação em formato ReDoc, que oferece uma apresentação mais limpa e organizada.
Personalizando a Documentação
Você pode adicionar descrições e metadados para melhorar a documentação:
from fastapi import FastAPI
app = FastAPI(
title="Minha API de Produtos",
description="Uma API simples para gerenciar produtos",
version="1.0.0"
)
@app.post("/produtos",
summary="Criar novo produto",
description="Cria um novo produto no sistema com nome, preço e categoria")
def criar_produto(produto: Produto):
return {"status": "criado", "produto": produto}
Tratamento de Erros e Status Codes
O tratamento de erros é fundamental para criar APIs robustas. O FastAPI oferece várias formas de lidar com erros.
Códigos de Status HTTP
Use códigos de status apropriados para diferentes situações:
from fastapi import FastAPI, HTTPException, status
app = FastAPI()
produtos_db = {
1: {"nome": "Notebook", "preco": 2500.00},
2: {"nome": "Mouse", "preco": 50.00}
}
@app.get("/produtos/{produto_id}")
def obter_produto(produto_id: int):
if produto_id not in produtos_db:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Produto não encontrado"
)
return produtos_db[produto_id]
@app.delete("/produtos/{produto_id}")
def deletar_produto(produto_id: int):
if produto_id not in produtos_db:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Produto não encontrado"
)
del produtos_db[produto_id]
return {"mensagem": "Produto deletado com sucesso"}
Manipuladores de Exceção Personalizados
Crie manipuladores customizados para diferentes tipos de erro:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
app = FastAPI()
class ProdutoNaoEncontradoError(Exception):
def __init__(self, produto_id: int):
self.produto_id = produto_id
@app.exception_handler(ProdutoNaoEncontradoError)
async def produto_nao_encontrado_handler(request: Request, exc: ProdutoNaoEncontradoError):
return JSONResponse(
status_code=404,
content={"erro": f"Produto {exc.produto_id} não foi encontrado"}
)
@app.get("/produtos/{produto_id}")
def obter_produto(produto_id: int):
if produto_id not in produtos_db:
raise ProdutoNaoEncontradoError(produto_id)
return produtos_db[produto_id]
Middlewares e CORS
Middlewares são componentes que processam requisições antes que cheguem aos seus endpoints. São úteis para logging, autenticação, e outras funcionalidades transversais.
Configurando CORS
CORS (Cross-Origin Resource Sharing) permite que sua API seja acessada de diferentes domínios:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# Configurar CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000", "http://127.0.0.1:3000"],
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE"],
allow_headers=["*"],
)
@app.get("/dados")
def obter_dados():
return {"dados": "Estes dados podem ser acessados via CORS"}
Middleware Personalizado
Crie middlewares personalizados para necessidades específicas:
import time
from fastapi import FastAPI, Request
app = FastAPI()
@app.middleware("http")
async def medir_tempo_requisicao(request: Request, call_next):
inicio = time.time()
response = await call_next(request)
tempo_processamento = time.time() - inicio
response.headers["X-Tempo-Processamento"] = str(tempo_processamento)
print(f"Requisição processada em {tempo_processamento:.4f} segundos")
return response
Testes Automatizados
Testes são essenciais para garantir que sua API funcione corretamente. O FastAPI facilita a criação de testes automatizados.
Configurando Testes
Instale as dependências de teste:
pip install pytest httpx
Crie um arquivo test_main.py
:
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_ler_raiz():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"mensagem": "Olá, mundo!"}
def test_criar_produto():
produto_teste = {
"nome": "Produto Teste",
"preco": 99.99,
"categoria": "teste",
"em_estoque": True
}
response = client.post("/produtos", json=produto_teste)
assert response.status_code == 200
dados = response.json()
assert dados["status"] == "criado"
assert dados["produto"]["nome"] == "Produto Teste"
def test_produto_nao_encontrado():
response = client.get("/produtos/999")
assert response.status_code == 404
assert "não encontrado" in response.json()["detail"]
Executando Testes
Execute os testes com:
pytest test_main.py -v
Resultado esperado:
test_main.py::test_ler_raiz PASSED
test_main.py::test_criar_produto PASSED
test_main.py::test_produto_nao_encontrado PASSED
Integração com Banco de Dados
Para aplicações reais, você precisará integrar sua API com um banco de dados. Vamos ver como fazer isso com SQLAlchemy.
Instalando Dependências
pip install sqlalchemy databases asyncpg
Configurando o Banco de Dados
Crie um arquivo database.py
:
from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String, Float, Boolean
from databases import Database
DATABASE_URL = "sqlite:///./produtos.db"
database = Database(DATABASE_URL)
metadata = MetaData()
produtos_table = Table(
"produtos",
metadata,
Column("id", Integer, primary_key=True),
Column("nome", String(100)),
Column("preco", Float),
Column("categoria", String(50)),
Column("em_estoque", Boolean, default=True)
)
engine = create_engine(DATABASE_URL)
metadata.create_all(engine)
Integrando com FastAPI
from fastapi import FastAPI
from database import database, produtos_table
from pydantic import BaseModel
app = FastAPI()
class Produto(BaseModel):
nome: str
preco: float
categoria: str
em_estoque: bool = True
class ProdutoResposta(BaseModel):
id: int
nome: str
preco: float
categoria: str
em_estoque: bool
@app.on_event("startup")
async def startup():
await database.connect()
@app.on_event("shutdown")
async def shutdown():
await database.disconnect()
@app.post("/produtos", response_model=ProdutoResposta)
async def criar_produto(produto: Produto):
query = produtos_table.insert().values(
nome=produto.nome,
preco=produto.preco,
categoria=produto.categoria,
em_estoque=produto.em_estoque
)
ultimo_id = await database.execute(query)
return {**produto.dict(), "id": ultimo_id}
@app.get("/produtos", response_model=list[ProdutoResposta])
async def listar_produtos():
query = produtos_table.select()
resultados = await database.fetch_all(query)
return [dict(resultado) for resultado in resultados]
Deploy e Produção
Quando sua API estiver pronta, você precisa colocá-la em produção. Existem várias opções para fazer deploy de APIs FastAPI.
Preparando para Produção
Crie um arquivo requirements.txt
com todas as dependências:
pip freeze > requirements.txt
Configure variáveis de ambiente em um arquivo .env
:
DATABASE_URL=postgresql://user:password@localhost/produtosdb
SECRET_KEY=sua-chave-secreta-muito-segura
DEBUG=False
Deploy com Docker
Crie um Dockerfile
:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Configurações de Produção
Para produção, use configurações otimizadas:
import os
from fastapi import FastAPI
# Configurações baseadas em variáveis de ambiente
DEBUG = os.getenv("DEBUG", "False").lower() == "true"
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./app.db")
app = FastAPI(
title="API de Produtos",
debug=DEBUG,
docs_url="/docs" if DEBUG else None, # Desabilitar docs em produção
redoc_url="/redoc" if DEBUG else None
)
Execute com Gunicorn para melhor performance:
pip install gunicorn
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000
Exemplo Prático Completo
Vamos criar uma API completa para gerenciar uma biblioteca de livros:
from fastapi import FastAPI, HTTPException, status
from pydantic import BaseModel, Field
from typing import List, Optional
import uuid
app = FastAPI(title="API Biblioteca", version="1.0.0")
# Modelos de dados
class LivroBase(BaseModel):
titulo: str = Field(..., min_length=1, max_length=200)
autor: str = Field(..., min_length=1, max_length=100)
ano_publicacao: int = Field(..., ge=1000, le=2024)
genero: str = Field(..., min_length=1, max_length=50)
disponivel: bool = True
class Livro(LivroBase):
id: str = Field(default_factory=lambda: str(uuid.uuid4()))
class LivroAtualizar(BaseModel):
titulo: Optional[str] = None
autor: Optional[str] = None
ano_publicacao: Optional[int] = None
genero: Optional[str] = None
disponivel: Optional[bool] = None
# Banco de dados em memória (para demonstração)
livros_db: List[Livro] = []
# Endpoints
@app.get("/", tags=["Raiz"])
def ler_raiz():
return {"mensagem": "API da Biblioteca - Gerencie seus livros!"}
@app.post("/livros", response_model=Livro, status_code=status.HTTP_201_CREATED, tags=["Livros"])
def criar_livro(livro: LivroBase):
novo_livro = Livro(**livro.dict())
livros_db.append(novo_livro)
print(f"Livro criado: {novo_livro.titulo}")
return novo_livro
@app.get("/livros", response_model=List[Livro], tags=["Livros"])
def listar_livros(disponivel: Optional[bool] = None, genero: Optional[str] = None):
livros_filtrados = livros_db
if disponivel is not None:
livros_filtrados = [l for l in livros_filtrados if l.disponivel == disponivel]
if genero:
livros_filtrados = [l for l in livros_filtrados if l.genero.lower() == genero.lower()]
return livros_filtrados
@app.get("/livros/{livro_id}", response_model=Livro, tags=["Livros"])
def obter_livro(livro_id: str):
for livro in livros_db:
if livro.id == livro_id:
return livro
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Livro não encontrado"
)
@app.put("/livros/{livro_id}", response_model=Livro, tags=["Livros"])
def atualizar_livro(livro_id: str, dados_atualizacao: LivroAtualizar):
for i, livro in enumerate(livros_db):
if livro.id == livro_id:
dados_atualizados = dados_atualizacao.dict(exclude_unset=True)
livro_atualizado = livro.copy(update=dados_atualizados)
livros_db[i] = livro_atualizado
print(f"Livro atualizado: {livro_atualizado.titulo}")
return livro_atualizado
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Livro não encontrado"
)
@app.delete("/livros/{livro_id}", tags=["Livros"])
def deletar_livro(livro_id: str):
for i, livro in enumerate(livros_db):
if livro.id == livro_id:
livro_removido = livros_db.pop(i)
print(f"Livro removido: {livro_removido.titulo}")
return {"mensagem": "Livro removido com sucesso"}
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Livro não encontrado"
)
# Endpoint de estatísticas
@app.get("/estatisticas", tags=["Estatísticas"])
def obter_estatisticas():
total_livros = len(livros_db)
livros_disponiveis = len([l for l in livros_db if l.disponivel])
generos = {}
for livro in livros_db:
generos[livro.genero] = generos.get(livro.genero, 0) + 1
return {
"total_livros": total_livros,
"livros_disponiveis": livros_disponiveis,
"livros_emprestados": total_livros - livros_disponiveis,
"distribuicao_generos": generos
}
Esta API completa permite:
- Criar, listar, obter, atualizar e deletar livros
- Filtrar livros por disponibilidade e gênero
- Ver estatísticas da biblioteca
- Validação automática de dados
- Documentação interativa automática
Perguntas Frequentes (FAQ)
1. O que é FastAPI?
FastAPI é um framework moderno para criar APIs em Python com alta performance e validação automática de dados.
2. Como posso começar com FastAPI?
Instale com pip install fastapi uvicorn
e crie um arquivo Python com suas rotas usando decoradores como @app.get()
.
3. FastAPI é mais rápido que Flask?
Sim, FastAPI é significativamente mais rápido que Flask, especialmente para operações assíncronas e validação de dados.
4. Preciso conhecer programação assíncrona para usar FastAPI?
Não é obrigatório. FastAPI funciona com funções síncronas normais, mas oferece suporte completo para async/await quando necessário.
5. Como o FastAPI gera documentação automática?
Usa os type hints do Python e modelos Pydantic para gerar automaticamente documentação OpenAPI, disponível em /docs e /redoc.
6. Posso usar FastAPI com bancos de dados?
Sim, FastAPI funciona com qualquer ORM ou biblioteca de banco de dados, incluindo SQLAlchemy, Tortoise ORM e MongoDB.
7. FastAPI é adequado para produção?
Absolutamente. É usado em produção por empresas como Netflix, Uber e Microsoft. Oferece alta performance e recursos empresariais.
8. Como implementar autenticação no FastAPI?
FastAPI oferece suporte nativo para JWT, OAuth2, cookies e outros métodos de autenticação através de dependências.