Este projeto é uma API REST para gerenciamento de pedidos e clientes, construída com FastAPI, SQLAlchemy e Pydantic. O banco de dados é configurável: SQLite (arquivo local, sem instalação) ou MySQL, escolhido por variável de ambiente, sem alterar código. O código é organizado em camadas (model, repository, service, controller, schema), cada uma com responsabilidade única.
- Arquitetura e camadas
- Padrões de projeto utilizados
- Protocolo REST/HTTP utilizado
- Estrutura de pastas e arquivos
- Instalação e configuração no Windows
- Escolhendo o banco de dados: SQLite ou MySQL
- Executando a aplicação
- Autenticação
- Rotas disponíveis
A aplicação segue uma arquitetura em camadas, onde cada uma só conhece a camada imediatamente abaixo dela. Uma requisição atravessa o sistema nesta ordem:
Cliente HTTP
│
▼
Controller → recebe a chamada da rota, delega ao service, converte erros de
negócio (ValueError) em respostas HTTP (404, 400, 401...)
│
▼
Service → regras de negócio: o que é obrigatório, o que pode ou não ser
atualizado, como um pedido se relaciona com seus itens
│
▼
Repository → acesso ao banco de dados (CRUD puro), sem nenhuma regra de
negócio embutida
│
▼
Model (ORM) → tabelas do banco, mapeadas como classes Python via SQLAlchemy
Por que separar assim? Cada camada pode ser substituída isoladamente. Por exemplo, o repository pode trocar de MySQL para SQLite (como este projeto agora permite) sem que service, controller ou rota percebam qualquer diferença — todos dependem apenas da interface do repository, não da implementação concreta.
| Camada | Pasta | Conhece o banco? | Conhece regra de negócio? | Conhece HTTP? |
|---|---|---|---|---|
| Model | models/ |
sim (é a tabela) | não | não |
| Repository | repositories/ |
sim | não | não |
| Service | services/ |
não (fala com o repository) | sim | não |
| Controller | controllers/ |
não | não (delega ao service) | sim |
| Schema | schemas/ |
não | não | sim (formato de entrada/saída) |
- Repository Pattern (repositories/igeneric_repository.py, repositories/generic_repository.py): isola o acesso a dados atrás de uma interface (
IGenericRepository). O service depende da interface, não da implementação — por isso trocar o banco de dados não exige alterar nenhum service. - Generic Repository (
Generic[T],TypeVar): uma única implementação de CRUD (GenericRepository) serve tanto paraPedidoquanto paraCliente.PedidoRepositoryeClienteRepositoryapenas informam qual modelo usar — evita duplicar create/read/update/delete para cada entidade. - Factory Pattern (controllers/factory.py):
ControllerFactorycentraliza a montagem da cadeiarepository → service → controllerpara cada requisição, evitando repetir esse código em cada rota doapp.py. - Dependency Injection: o
Depends()do FastAPI injeta a sessão de banco (get_db) e os controllers automaticamente, por requisição — cada requisição recebe sua própria sessão, fechada ao final mesmo se ocorrer erro. - DTO / separação schema-model: os dados que entram (
*CreateSchema,*UpdateSchema) e saem (*OutSchema) pela API nunca são o objeto ORM diretamente — são schemas Pydantic dedicados, o que evita expor detalhes internos da tabela (e permite validar o formato antes de qualquer regra de negócio rodar). - Strategy implícita na configuração de banco (config/database.py): a função
_build_database_url()decide, a partir da variávelDB_BACKEND, qual string de conexão montar — SQLite ou MySQL —, sem que o restante da aplicação precise saber qual dos dois está em uso.
A API segue os princípios REST sobre HTTP/1.1, conforme descrito em IWS/readme.md:
- Recursos identificados por URL:
/pedidos,/pedidos/{id},/clientes,/clientes/{id}. - Verbos HTTP com significado semântico:
Verbo Uso no projeto GETler um recurso (não altera estado) POSTcriar um novo recurso PUTatualizar um recurso existente DELETEremover um recurso - Stateless: cada requisição carrega tudo o que o servidor precisa (inclusive a chave de API no header) — nenhuma sessão é mantida em memória entre requisições.
- Corpo em JSON: tanto o corpo de entrada (
POST/PUT) quanto o de saída são JSON, validados por schemas Pydantic. - Códigos de status HTTP com significado:
Código Situação 200 OKleitura ou atualização bem-sucedida 201 Createdrecurso criado com sucesso 204 No Contentremoção bem-sucedida (sem corpo de resposta) 400 Bad Requestdado de negócio inválido (ex.: pedido sem itens) 401 Unauthorizedheader X-API-Keyausente ou incorreto404 Not Foundrecurso inexistente 422 Unprocessable Entitycorpo da requisição não corresponde ao schema esperado (gerado automaticamente pelo FastAPI/Pydantic) - Documentação auto-descritiva: o FastAPI gera a especificação OpenAPI automaticamente a partir das rotas e schemas, exposta em
/docs(Swagger UI) e/redoc.
IWS/
└── rest/
├── app.py # Ponto de entrada: rotas FastAPI e injeção de dependências
├── config/
│ ├── database.py # Monta a conexão (SQLite ou MySQL) conforme DB_BACKEND
│ └── security.py # Verificação da chave de API
├── models/
│ ├── base.py # Base declarativa do SQLAlchemy
│ ├── cliente.py # Tabela `cliente`
│ ├── pedido.py # Tabela `pedido`
│ └── item_pedido.py # Tabela `item_pedido`
├── repositories/
│ ├── igeneric_repository.py # Contrato genérico de acesso a dados
│ ├── generic_repository.py # Implementação genérica do CRUD
│ ├── icliente_repository.py / cliente_repository.py
│ └── ipedido_repository.py / pedido_repository.py
├── services/
│ ├── cliente_service.py # Regras de negócio de cliente
│ └── pedido_service.py # Regras de negócio de pedido
├── controllers/
│ ├── cliente_controller.py # Ponte entre rota e service, traduz erros em HTTP
│ ├── pedido_controller.py
│ └── factory.py # Monta a cadeia repository → service → controller
├── schemas/
│ └── schema.py # Schemas Pydantic de entrada e saída
├── requirements.txt # Dependências de execução
└── .env.example # Modelo de variáveis de ambiente
Todos os comandos abaixo são para PowerShell. O caminho do projeto é IWS\rest dentro do repositório clonado.
Este projeto é validado com Python 3.12. Se ainda não tiver essa versão instalada:
winget install --id Python.Python.3.12 --source wingetUm ambiente virtual isola as dependências deste projeto do restante do sistema.
cd caminho\para\IWS\rest
py -3.12 -m venv .venv
.\.venv\Scripts\Activate.ps1Se o PowerShell bloquear a ativação por política de execução de scripts, rode uma vez (como usuário atual, não exige administrador):
Set-ExecutionPolicy -Scope CurrentUser RemoteSignedCom o ambiente ativado, o prompt passa a exibir (.venv) no início da linha.
pip install -r requirements.txtIsso instala FastAPI, Uvicorn, SQLAlchemy, Pydantic, python-dotenv e o driver do MySQL. O driver do MySQL só é necessário se você for usar DB_BACKEND=mysql — para rodar apenas com SQLite (o padrão), esse pacote fica instalado mas inerte, não é preciso removê-lo.
Copy-Item .env.example .envAbra o .env gerado em um editor de texto e ajuste os valores conforme a seção seguinte.
A variável DB_BACKEND no .env decide qual banco a aplicação usa. Nenhuma outra alteração de código é necessária para trocar de um para o outro.
Não exige instalar nem configurar nenhum servidor de banco de dados — é um único arquivo local.
DB_BACKEND=sqlite
SQLITE_PATH=./db_pedidos.dbAo rodar a aplicação, o arquivo db_pedidos.db (e as tabelas dentro dele) são criados automaticamente na primeira execução, no diretório onde o comando for executado.
Use quando quiser um comportamento mais próximo de um ambiente de produção real, ou já tiver um MySQL disponível.
- Instale o MySQL, se necessário:
winget install --id Oracle.MySQL --source winget
- Crie o banco de dados (via MySQL Workbench,
mysqlCLI, ou outra ferramenta de sua preferência):CREATE DATABASE db_pedidos;
- No
.env:DB_BACKEND=mysql DB_USER=root DB_PASSWORD=sua_senha DB_HOST=localhost DB_NAME=db_pedidos
As tabelas (cliente, pedido, item_pedido) também são criadas automaticamente na primeira execução, caso ainda não existam.
O
.envnunca deve ser versionado no Git — ele já está listado no.gitignore.
Com o ambiente virtual ativado e o .env configurado:
python app.pySaída esperada: o Uvicorn informa que o servidor está no ar em http://localhost:8000.
Acesse a documentação interativa, gerada automaticamente a partir das rotas e schemas:
- Swagger UI: http://localhost:8000/docs
- Redoc: http://localhost:8000/redoc
Para parar o servidor, pressione Ctrl+C no terminal.
# Sem autenticação
Invoke-RestMethod -Uri http://localhost:8000/health
# Com autenticação (X-API-Key deve bater com o valor de API_KEY no .env)
$headers = @{ "X-API-Key" = "changeme" }
Invoke-RestMethod -Uri http://localhost:8000/clientes -Headers $headers
Invoke-RestMethod -Uri http://localhost:8000/clientes -Method Post -Headers $headers `
-ContentType "application/json" -Body '{"nome":"Ana","idade":30}'Todas as rotas de /pedidos e /clientes exigem o header X-API-Key, com o valor configurado em API_KEY no .env. Requisições sem a chave, ou com uma chave incorreta, recebem 401 Unauthorized. O endpoint GET /health é público, para uso por ferramentas de monitoramento.
| Método | Rota | Autenticação | Descrição |
|---|---|---|---|
| GET | /health |
não | Verifica se a aplicação está no ar |
| GET | /pedidos |
sim | Lista pedidos (aceita skip e limit) |
| GET | /pedidos/{id} |
sim | Detalha um pedido |
| POST | /pedidos |
sim | Cria um novo pedido com seus itens |
| PUT | /pedidos/{id} |
sim | Atualiza cliente, data e/ou itens de um pedido |
| DELETE | /pedidos/{id} |
sim | Remove um pedido |
| GET | /clientes |
sim | Lista clientes (aceita skip e limit) |
| GET | /clientes/{id} |
sim | Detalha um cliente |
| POST | /clientes |
sim | Cria um novo cliente |
| PUT | /clientes/{id} |
sim | Atualiza nome e/ou idade de um cliente |
| DELETE | /clientes/{id} |
sim | Remove um cliente |
A paginação (skip/limit) evita carregar a tabela inteira em uma única resposta; os valores padrão são skip=0 e limit=100.