📚 Módulo 02: Backend - Setup Inicial, Alembic e Seeders
Para iniciar o desenvolvimento do backend com FastAPI, precisamos estruturar o ecossistema de dependências, configurar as variáveis de conexão com o banco de dados, configurar o motor de migrações Alembic e criar um script Seeder automático para popular nossa base de dados com massa de teste didática.
📦 1. Dependências do Projeto (requirements.txt)
Crie o arquivo requirements.txt na raiz do seu repositório backend:
fastapi==0.110.0
uvicorn[standard]==0.28.0
sqlalchemy[asyncio]==2.0.28
asyncpg==0.29.0
aiosqlite==0.20.0
alembic==1.13.1
pydantic[email]==2.6.4
pyjwt[crypto]==2.8.0
passlib[bcrypt]==1.7.4
python-dotenv==1.0.1
Instale as dependências localmente em seu ambiente virtual com o comando:
pip install -r requirements.txt
⚙️ 2. Configurações de Conexão com o Banco de Dados
Criaremos uma classe de configuração dinâmica que lê as variáveis do arquivo .env para determinar se usaremos um banco de dados leve local para desenvolvimento (SQLite assíncrono) ou o banco serverless de produção (Neon PostgreSQL).
Crie o arquivo app/config.py:
import os
from pydantic_settings import BaseSettings
from dotenv import load_dotenv
load_dotenv()
class Settings(BaseSettings):
# Conexão padrão: SQLite assíncrono local se nenhuma URL for definida
DATABASE_URL: str = os.getenv(
"DATABASE_URL",
"sqlite+aiosqlite:///./tecloja.db"
)
# Chave secreta de assinatura do JWT e tempo de expiração
JWT_SECRET: str = os.getenv("JWT_SECRET", "super-secret-key-of-tecloja-api")
JWT_ALGORITHM: str = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES: int = 120
settings = Settings()
🗄️ 3. Versionamento de Esquema com Alembic
Em grandes projetos, alterar tabelas rodando DDL manual no banco de dados é um antipadrão perigoso. O Alembic rastreia as alterações das classes do SQLAlchemy e gera scripts Python organizados no tempo para subir ou reverter alterações estruturais de forma totalmente automatizada.
Passo 1: Inicializar o Alembic
flowchart TD
A[SQLAlchemy Models] -->|MetaDados| B(Alembic env.py)
C[alembic revision --autogenerate] --> B
B --> D[Script de Migração Python]
D -->|alembic upgrade head| E[(Banco de Dados Físico)]
style E fill:#f96,stroke:#333,stroke-width:2px
Na raiz do projeto backend, execute o comando:
alembic init alembic
Isso criará uma pasta chamada alembic/ e o arquivo alembic.ini.
Passo 2: Configurar o Target Metadata do SQLAlchemy
Para que o Alembic consiga mapear nossas classes automaticamente, abra o arquivo alembic/env.py e altere as linhas de importação para carregar as nossas entidades e a classe Base:
# Importe a classe Base e os modelos
from app.models.base import Base
from app.models.produto import Categoria, Produto
from app.models.pedido import Cliente, Pedido, ItemPedido
from app.models.usuario import Usuario
# Defina o metadata para autogeração
target_metadata = Base.metadata
Passo 3: Configurar a conexão do banco dinamicamente
Ainda em alembic/env.py, encontre as funções de execução e certifique-se que o Alembic use a URL de conexão definida em nosso arquivo app/config.py:
from app.config import settings
def run_migrations_offline() -> None:
url = settings.DATABASE_URL
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
# ... resto do código ...
Passo 4: Gerar e Aplicar a Primeira Migração
Para que o Alembic varra nossas entidades e escreva o script SQL de criação de tabelas, execute:
alembic revision --autogenerate -m "criar schema inicial tecloja"
Agora, aplique as migrações físicas na base de dados com o comando:
alembic upgrade head
O Alembic criará o arquivo de banco tecloja.db com todas as tabelas e chaves estrangeiras modeladas no Módulo 01!
🌱 4. O Data Seeder Automatizado
Nas aulas práticas, é vital que os alunos iniciem os testes com dados válidos preexistentes. Escreveremos um script Python que cria as categorias de tecnologia, insere 5 produtos eletrônicos premium no estoque e cadastra os perfis de usuários com senhas criptografadas.
Crie o arquivo app/seeders/data_seeder.py:
import asyncio
from decimal import Decimal
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
from passlib.context import CryptContext
from app.config import settings
from app.models.base import Base
from app.models.produto import Categoria, Produto
from app.models.pedido import Cliente
from app.models.usuario import Usuario
# Criptografia de senhas
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
async def seed_data():
engine = create_async_engine(settings.DATABASE_URL, echo=True)
async_session = async_sessionmaker(engine, expire_on_commit=False)
print("🌱 Iniciando o Seeding de dados da TecLoja 02...")
async with async_session() as session:
async with session.begin():
# 1. Criar Categorias
smartphones = Categoria(nome="Smartphones")
notebooks = Categoria(nome="Notebooks")
acessorios = Categoria(nome="Acessórios")
session.add_all([smartphones, notebooks, acessorios])
# 2. Criar Produtos Eletrônicos Premium
p1 = Produto(
nome="iPhone 15 Pro Max",
descricao="Tela Super Retina XDR, chip A17 Pro e câmera de 48MP.",
preco=Decimal("9499.00"),
estoque=10,
categoria=smartphones
)
p2 = Produto(
nome="Galaxy S24 Ultra",
descricao="Processador Snapdragon 8 Gen 3 e inteligência artificial Galaxy AI.",
preco=Decimal("8499.00"),
estoque=8,
categoria=smartphones
)
p3 = Produto(
nome="MacBook Pro 16 M3 Max",
descricao="Chip M3 Max com CPU de 16 núcleos, GPU de 40 núcleos e 48GB RAM.",
preco=Decimal("34999.00"),
estoque=3,
categoria=notebooks
)
p4 = Produto(
nome="Notebook Dell XPS 13",
descricao="Processador Intel Core Ultra 7, 16GB RAM e SSD de 1TB.",
preco=Decimal("11999.00"),
estoque=5,
categoria=notebooks
)
p5 = Produto(
nome="Headphone Sony WH-1000XM5",
descricao="Cancelamento de ruído ativo premium e até 30 horas de bateria.",
preco=Decimal("2199.00"),
estoque=15,
categoria=acessorios
)
session.add_all([p1, p2, p3, p4, p5])
# 3. Criar Clientes Didáticos
c1 = Cliente(nome="Maria Silva", email="maria@gmail.com")
c2 = Cliente(nome="José Souza", email="jose@gmail.com")
session.add_all([c1, c2])
# 4. Criar Usuários do Sistema com Senhas Criptografadas
admin = Usuario(
username="admin@tecloja.com",
password_hash=pwd_context.hash("admin123"),
papel="ROLE_ADMIN"
)
user = Usuario(
username="cliente@tecloja.com",
password_hash=pwd_context.hash("cliente123"),
papel="ROLE_USER"
)
session.add_all([admin, user])
await session.commit()
await engine.dispose()
print("✨ Seeding concluído com sucesso!")
if __name__ == "__main__":
asyncio.run(seed_data())
Execute o seeder em seu terminal:
python -m app.seeders.data_seeder
✅ Pré-Requisitos deste Módulo
Antes de inicializar as migrações e o seeder, certifique-se de que:
- As entidades JPA do SQLAlchemy mapeadas no Módulo 01 estão salvas nos arquivos corretos sob a pasta
app/models/. - O seu ambiente virtual do Python (
venv) está ativo e atualizado.
🤔 Por que fizemos assim?
- Por que usar
BaseSettingsdo Pydantic? Carregar configurações de sistema lendo variáveis do sistema ou de um arquivo.envlocal garante segurança (separação de credenciais de produção e local) e realiza a coerção automática de tipos (ex: converter o tempo do token JWT de string para número de minutos de forma segura). - Por que gerenciar alterações com o Alembic? A evolução estrutural das tabelas do banco de dados (DDL) deve caminhar sob controle de versão assim como o código-fonte da aplicação. O Alembic monitora a classe Base declarativa do SQLAlchemy e gera scripts versionados e sequenciais de migração, facilitando a subida de versões ou o rollback em ambientes de produção.
- Por que criptografar senhas com Passlib e BCrypt? Gravar senhas de forma literal no banco de dados é um dos maiores desvios de segurança cibernética. O algoritmo de hash BCrypt insere um fator de lentidão (salt dinâmico) adaptativo para impossibilitar ataques computacionais de dicionário ou de força bruta.
🔍 Checkpoint
- Instalação de Dependências: Execute
pip install -r requirements.txte verifique se as bibliotecas foram baixadas sem erros. - Migração Inicial: Execute
alembic init alembic, ajuste o arquivoenv.pye execute:alembic revision --autogenerate -m "criar schema inicial tecloja" alembic upgrade headConfirme se o arquivo físico
tecloja.dbfoi criado no diretório raiz do backend. - Seeder de Testes: Execute o comando de seeding:
python -m app.seeders.data_seederCertifique-se de que a mensagem final
"Seeding concluído com sucesso!"é exibida no console do terminal.
⚠️ Erros Comuns
| Erro | Causa | Solução |
|---|---|---|
ModuleNotFoundError: No module named 'app' |
Tentativa de executar um script diretamente de sua pasta física interna (ex: rodar a partir da pasta /seeders/), quebrando as importações relativas. |
No terminal, execute sempre os comandos a partir da pasta raiz do repositório backend (tecloja-backend) usando o parâmetro -m (ex: python -m app.seeders.data_seeder). |
alembic.util.exc.CommandError: Target database is not up to date |
O banco de dados físico possui registros ou revisões desalinhadas com o histórico de scripts locais do Alembic. | Atualize a versão do banco local rodando alembic upgrade head antes de gerar novas revisões automáticas, ou limpe o banco local deletando o arquivo .db e gerando as revisões do zero. |
🏁 Conclusão e Próximos Passos
Incrível! Nossa infraestrutura de banco de dados assíncrona está configurada, versionada com o Alembic e povoada com dados premium de testes didáticos via script Python.
No Módulo 03, entraremos nos pilares de Engenharia de Software. Criaremos a camada de isolamento do contrato utilizando o padrão DTO com schemas do Pydantic v2 e programaremos um manipulador global de exceções para garantir que nenhum erro interno Python seja exposto de forma insegura, retornando sempre mensagens padronizadas em JSON para o frontend.