FastAPI
FastAPI
🔹 Conhecimentos em Python
● Sintaxe básica
● Funções
● Manipulação de arquivos
● Módulos e pacotes
🔹 Primeiro projeto
Crie um arquivo main.py:
app = FastAPI()
@app.get("/")
def read_root():
return {"mensagem": "Olá, mundo!"}
Rode com:
Pacote Função
● No backend, ao definir rotas, indicamos quais URLs e métodos serão tratados por
quais funções.
a) GET
● É uma operação segura e idempotente (não altera o estado do servidor, pode ser
repetida sem efeitos colaterais).
b) POST
c) PUT
● É idempotente — repetir a mesma requisição PUT tem o mesmo efeito que uma
única.
d) DELETE
● Também é idempotente — deletar o mesmo recurso várias vezes não gera erros
adicionais (o recurso já estará removido).
5. Idempotência e segurança
● Idempotente: mesmo efeito ao repetir a mesma requisição várias vezes.
✅ 1. Setup básico
Crie um arquivo chamado main.py:
app = FastAPI()
# Modelo de dados
class Item(BaseModel):
id: int
nome: str
descricao: str = ""
▶️ Executar a API
Terminal:
bash
CopiarEditar
uvicorn main:app --reload
📍
Abra o navegador em:
http://127.0.0.1:8000/docs → Interface interativa para testar todas essas rotas!
1. O que é Pydantic?
● Pydantic é uma biblioteca Python para validação de dados e parsing (análise e
conversão).
2. O que é BaseModel?
● BaseModel é a classe base do Pydantic para definir modelos de dados.
● Você cria classes que herdam de BaseModel e define os campos (atributos) com
seus tipos.
● Se os dados não estiverem corretos (tipo errado, campo obrigatório faltando, etc),
uma exceção é lançada automaticamente, gerando resposta 422 (Unprocessable
Entity).
📌 Exemplo básico
from pydantic import BaseModel
class Usuario(BaseModel):
id: int
nome: str
email: str
ativo: bool = True # valor padrão
✅ Como o FastAPI usa isso?
POST com validação automática:
python
CopiarEditar
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Usuario(BaseModel):
id: int
nome: str
email: str
ativo: bool = True
@app.post("/usuarios")
def criar_usuario(usuario: Usuario):
return {"mensagem": "Usuário criado", "dados": usuario}
FastAPI responde:
json
CopiarEditar
{
"mensagem": "Usuário criado",
"dados": {
"id": 1,
"nome": "Camylla",
"email": "[email protected]",
"ativo": true
}
}
json
CopiarEditar
{
"id": "abc",
"nome": 123,
"email": true
}
A resposta será:
json
CopiarEditar
{
"detail": [
{
"loc": ["body", "id"],
"msg": "value is not a valid integer",
"type": "type_error.integer"
},
...
]
}
🛠 Dicas avançadas
✔️ Campos opcionais:
python
CopiarEditar
from typing import Optional
class Usuario(BaseModel):
nome: str
idade: Optional[int] = None
✔️ Validação de e-mail:
python
CopiarEditar
from pydantic import EmailStr
class Usuario(BaseModel):
nome: str
email: EmailStr # valida se é e-mail válido
● Exemplo:
○ URL: /usuarios/123
Características
● Inseridos diretamente na URL.
● São opcionais.
● Exemplo:
○ URL: /usuarios?idade=30&cidade=SP
Características
● Permitem enviar dados flexíveis para a API, como filtros, buscas, paginação.
5. No FastAPI
● Path Parameters são declarados na definição da rota com chaves {} e passados
como argumentos na função.
● Query Parameters são declarados como parâmetros da função com valores padrão
ou opcionais.
Exemplo:
python
CopiarEditar
from fastapi import FastAPI
app = FastAPI()
@app.get("/itens/{item_id}")
def ler_item(item_id: int):
return {"item_id": item_id}
📝 Diferenças rápidas
Tipo Na URL Obrigatório Exemplo
?
1. Middleware
O que é Middleware?
● Funciona como um filtro ou interceptador das requisições antes que cheguem nas
rotas, e das respostas antes que sejam enviadas ao cliente.
● Autenticação e autorização
Como funciona?
● Toda requisição passa pelo middleware antes de chegar na função que trata a rota.
● O middleware pode permitir que a requisição prossiga, modificar os dados, ou
bloquear a requisição.
● Permite gerenciar o ciclo de vida das dependências (ex: abrir e fechar conexão de
banco).
Benefícios
3. Resumo prático
app = FastAPI()
@app.middleware("http")
async def medir_tempo_request(request: Request, call_next):
inicio = time.time()
response = await call_next(request) # chama a próxima etapa
(rota, outro middleware)
duracao = time.time() - inicio
response.headers["X-Duration-Seconds"] = str(duracao)
return response
@app.get("/")
async def raiz():
return {"mensagem": "Olá, mundo!"}
Aqui o middleware mede o tempo que a requisição levou para ser processada e adiciona
esse dado no header da resposta.
app = FastAPI()
def obter_usuario_atual():
return {"nome": "Camylla", "id": 1}
@app.get("/perfil")
def perfil(usuario: dict = Depends(obter_usuario_atual)):
return {"perfil_usuario": usuario}
@app.get("/itens")
def listar_itens(db=Depends(get_db)):
return {"db": db, "itens": ["item1", "item2"]}
● get_db é um gerador que cria e limpa recursos.
1. O que é CRUD?
CRUD é o acrônimo para as operações básicas que uma aplicação faz num banco de
dados:
● Permite trabalhar com banco de dados usando objetos Python em vez de escrever
SQL manualmente.
● Faz o mapeamento entre tabelas do banco e classes/objetos do seu código.
● PostgreSQL
● Você cria uma engine para conectar no banco (ex: SQLite, PostgreSQL).
● Cria uma sessão (session) para gerenciar as transações (consultas, inserções etc).
● Para validar e serializar os dados enviados e recebidos pela API, você usa modelos
Pydantic.
● Eles são diferentes dos modelos SQLAlchemy (que são para banco), mas espelham
os campos principais.
● Read:
● Update:
○ Consulta o objeto.
● Delete:
○ Consulta o objeto.
○ Deleta da sessão.
○ Comita a operação.
6. Benefícios de usar FastAPI com SQLAlchemy para
CRUD
● Integração natural com validação via Pydantic.
1. Instale as dependências
/app
├── main.py
├── database.py
├── models.py
└── schemas.py
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread":
False}
)
Base = declarative_base()
class Item(Base):
__tablename__ = "itens"
class ItemBase(BaseModel):
nome: str
descricao: str | None = None
class ItemCreate(ItemBase):
pass
class Item(ItemBase):
id: int
class Config:
orm_mode = True
6. main.py — CRUD e rotas
Base.metadata.create_all(bind=engine)
app = FastAPI()
@app.post("/itens/", response_model=schemas.Item)
def criar_item(item: schemas.ItemCreate, db: Session =
Depends(get_db)):
db_item = models.Item(nome=item.nome, descricao=item.descricao)
db.add(db_item)
db.commit()
db.refresh(db_item)
return db_item
@app.get("/itens/", response_model=list[schemas.Item])
def ler_itens(skip: int = 0, limit: int = 10, db: Session =
Depends(get_db)):
itens = db.query(models.Item).offset(skip).limit(limit).all()
return itens
@app.get("/itens/{item_id}", response_model=schemas.Item)
def ler_item(item_id: int, db: Session = Depends(get_db)):
item = db.query(models.Item).filter(models.Item.id ==
item_id).first()
if not item:
raise HTTPException(status_code=404, detail="Item não
encontrado")
return item
@app.put("/itens/{item_id}", response_model=schemas.Item)
def atualizar_item(item_id: int, item: schemas.ItemCreate, db:
Session = Depends(get_db)):
db_item = db.query(models.Item).filter(models.Item.id ==
item_id).first()
if not db_item:
raise HTTPException(status_code=404, detail="Item não
encontrado")
db_item.nome = item.nome
db_item.descricao = item.descricao
db.commit()
db.refresh(db_item)
return db_item
@app.delete("/itens/{item_id}")
def deletar_item(item_id: int, db: Session = Depends(get_db)):
db_item = db.query(models.Item).filter(models.Item.id ==
item_id).first()
if not db_item:
raise HTTPException(status_code=404, detail="Item não
encontrado")
db.delete(db_item)
db.commit()
return {"mensagem": "Item deletado com sucesso"}
7. Rodando a aplicação
8. Testando
● Abra no navegador:
http://127.0.0.1:8000/docs
para acessar a interface interativa Swagger UI.
Teoria
OAuth2
● Protocolo padrão para autorização, permite que apps acessem recursos protegidos
em nome do usuário.
● É complexo, mas seguro para apps que precisam acessar APIs externas (ex: login
via Google).
● Usado para autenticação: servidor gera um token com dados do usuário, que é
enviado no cabeçalho das requisições.
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
SECRET_KEY = "segredo_supersecreto"
@app.post("/token")
def login(form_data: OAuth2PasswordRequestForm = Depends()):
# Aqui você validaria usuário e senha no banco
if form_data.username != "usuario" or form_data.password !=
"senha":
raise HTTPException(status_code=400, detail="Credenciais
inválidas")
token = criar_token({"sub": form_data.username},
timedelta(minutes=30))
return {"access_token": token, "token_type": "bearer"}
@app.get("/usuario")
def ler_usuario(token: str = Depends(oauth2_scheme)):
try:
payload = jwt.decode(token, SECRET_KEY,
algorithms=["HS256"])
usuario = payload.get("sub")
if usuario is None:
raise HTTPException(status_code=401, detail="Token
inválido")
return {"usuario": usuario}
except jwt.PyJWTError:
raise HTTPException(status_code=401, detail="Token inválido
ou expirado")
2. Upload de arquivos
Teoria
● APIs permitem que clientes enviem arquivos (imagens, documentos).
app = FastAPI()
@app.post("/upload")
async def upload_arquivo(file: UploadFile = File(...)):
conteudo = await file.read()
with open(f"arquivos/{file.filename}", "wb") as f:
f.write(conteudo)
return {"filename": file.filename, "content_type":
file.content_type}
Teoria
CORS (Cross-Origin Resource Sharing)
● Segurança dos navegadores que bloqueia requisições de origens diferentes
(domínios).
● API pode liberar CORS para permitir que sites externos acessem seus recursos.
Versionamento de API
● Boas práticas indicam versionar APIs (/v1/, /v2/) para permitir evolução sem
quebrar clientes antigos.
Exemplos simples
CORS no FastAPI
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # ou lista de domínios permitidos
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
Versionamento básico pela URL
python
CopiarEditar
from fastapi import APIRouter, FastAPI
app = FastAPI()
v1 = APIRouter(prefix="/v1")
v2 = APIRouter(prefix="/v2")
@v1.get("/produtos")
def produtos_v1():
return {"versao": "v1", "produtos": []}
@v2.get("/produtos")
def produtos_v2():
return {"versao": "v2", "produtos": ["novo"]}
app.include_router(v1)
app.include_router(v2)
/app
/routers
usuarios.py
produtos.py
/models
usuario.py
produto.py
/schemas
usuario.py
produto.py
main.py