Uma solução completa de microsserviços para gerenciamento escolar desenvolvida com Flask, seguindo o padrão arquitetural MVC (Model-View-Controller). O sistema é composto por três microsserviços independentes que se comunicam via HTTP REST API, permitindo escalabilidade e manutenção independente de cada serviço.
- Descrição da API
- Arquitetura de Microsserviços
- Integração entre Serviços
- Tecnologias Utilizadas
- Estrutura do Projeto
- Instruções de Execução com Docker
- Documentação da API
- Endpoints dos Microsserviços
O sistema é dividido em três microsserviços independentes, cada um com sua própria base de dados e responsabilidades específicas:
Responsável pelo gerenciamento das entidades principais do sistema escolar:
- Professores: CRUD completo para cadastro e gerenciamento de professores
- Turmas: CRUD completo para gestão de turmas escolares
- Alunos: CRUD completo para gestão de alunos
Base de dados: gerenciamento.db (SQLite)
Responsável pelo gerenciamento acadêmico:
- Atividades: CRUD de atividades escolares vinculadas a turmas e professores
- Notas: CRUD de notas dos alunos vinculadas às atividades
Base de dados: atividades.db (SQLite)
Integrações: Valida a existência de professores, turmas e alunos consultando o microsserviço de Gerenciamento via HTTP.
Responsável pelo gerenciamento de reservas:
- Reservas: CRUD de reservas de salas
Base de dados: reservas.db (SQLite)
O projeto segue uma arquitetura de microsserviços com as seguintes características:
- Cada microsserviço possui seu próprio código-fonte, banco de dados e dependências
- Podem ser desenvolvidos, testados e implantados independentemente
- Falhas em um serviço não afetam diretamente os outros
Todos os microsserviços seguem a arquitetura MVC:
Microsserviço/
├── models/ # Model: Entidades e acesso ao banco de dados
├── controllers/ # Controller: Lógica de negócio e validações
└── api/ # View: Rotas HTTP e interface REST
- Os microsserviços se comunicam via requisições HTTP REST
- Utiliza a biblioteca
requestsdo Python - Comunicação através de DNS interno do Docker (nomes dos containers)
Cada microsserviço possui sua própria base de dados SQLite:
gerenciamento.db: Dados de professores, turmas e alunosatividades.db: Dados de atividades e notasreservas.db: Dados de reservas
- Cada microsserviço roda em um container Docker isolado
- Orquestração via Docker Compose
- Rede privada
backendpara comunicação entre containers
┌─────────────────────────────────────────────────────────────────┐
│ Cliente (Swagger UI) │
└────────┬─────────────────┬─────────────────┬────────────────────┘
│ │ │
│ :5000 │ :5001 │ :5002
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Gerenciamento │ │ Atividades │ │ Reservas │
│ Microsserviço │ │ Microsserviço │ │ Microsserviço │
├─────────────────┤ ├─────────────────┤ ├─────────────────┤
│ • Professores │ │ • Atividades │ │ • Reservas │
│ • Turmas │ │ • Notas │ │ │
│ • Alunos │ │ │ │ │
├─────────────────┤ ├─────────────────┤ ├─────────────────┤
│ Flask + SQLite │ │ Flask + SQLite │ │ Flask + SQLite │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
└───────────────────┴───────────────────┘
Rede Docker: backend
O microsserviço de Atividades precisa validar se professores, turmas e alunos existem antes de criar atividades ou notas. Essa validação é feita através de requisições HTTP ao microsserviço de Gerenciamento.
Exemplo: Criação de uma Atividade
# No controller de atividades (ctrls_atividades.py)
def validar_professor(professor_id):
"""Valida se o professor existe no microsserviço de Gerenciamento"""
try:
response = requests.get(f'http://gerenciamento:5000/professores/{professor_id}')
if response.status_code == 200:
return True, "Professor encontrado"
else:
return False, "Professor não encontrado"
except requests.exceptions.RequestException as e:
return False, f"Erro de conexão: {e}"
def validar_turma(turma_id):
"""Valida se a turma existe no microsserviço de Gerenciamento"""
try:
response = requests.get(f'http://gerenciamento:5000/turmas/{turma_id}')
if response.status_code == 200:
return True, "Turma encontrada"
else:
return False, "Turma não encontrada"
except requests.exceptions.RequestException as e:
return False, f"Erro de conexão: {e}"- Cliente faz POST para
/atividadesno microsserviço de Atividades (porta 5001) - Controller de Atividades valida os dados recebidos
- Valida o professor: Faz GET para
http://gerenciamento:5000/professores/{id} - Valida a turma: Faz GET para
http://gerenciamento:5000/turmas/{id} - Se ambas validações passarem, cria a atividade no banco
atividades.db - Retorna resposta ao cliente
Cliente → POST /atividades (porta 5001)
↓
Microsserviço Atividades
↓
GET /professores/1 → Microsserviço Gerenciamento
↓
GET /turmas/5 → Microsserviço Gerenciamento
↓
Salva atividade.db
↓
Retorna 201 Created
- Cliente faz POST para
/notasno microsserviço de Atividades - Controller de Notas valida os dados
- Valida o aluno: Faz GET para
http://gerenciamento:5000/alunos/{id} - Valida a atividade: Busca localmente no banco
atividades.db - Cria a nota vinculada à atividade
- Retorna resposta ao cliente
- Cliente faz POST para
/reservasno microsserviço de Gerenciamento - Controller de Reservas valida os dados
- Valida a turma: Faz GET para
http://gerenciamento:5000/turmas/{id} - Se a validação passar, cria a reserva no banco
reservas.db - Retorna resposta ao cliente
O Docker Compose cria uma rede privada backend onde os containers se comunicam usando seus nomes:
http://gerenciamento:5000→ Container do microsserviço de Gerenciamentohttp://atividades:5001→ Container do microsserviço de Atividadeshttp://reservas:5002→ Container do microsserviço de Reservas
Não é necessário usar IP, pois o Docker resolve automaticamente o nome do container para o IP interno.
Os microsserviços implementam tratamento robusto de erros:
try:
response = requests.get(f'http://gerenciamento:5000/professores/{professor_id}')
if response.status_code == 200:
return True, "Professor encontrado"
else:
return False, f"Professor não encontrado. Status: {response.status_code}"
except requests.exceptions.RequestException as e:
return False, f"Erro de conexão com Gerenciamento: {e}"Se o microsserviço de Gerenciamento estiver offline, a criação da atividade falhará com uma mensagem clara de erro.
- Flask 3.1.2 - Framework web Python minimalista e poderoso
- SQLAlchemy 2.0.43 - ORM para manipulação do banco de dados
- Flask-SQLAlchemy 3.1.1 - Integração Flask + SQLAlchemy
- Flasgger 0.9.7.1 - Documentação Swagger/OpenAPI automática
- Requests 2.31.0 - Cliente HTTP para comunicação entre microsserviços
- SQLite - Banco de dados embutido, um para cada microsserviço
- Docker - Containerização de aplicações
- Docker Compose - Orquestração de múltiplos containers
- Python 3.9+ - Linguagem de programação
Mvc-Flask/
├── 📂 atividades/ # Microsserviço de Atividades
│ ├── Dockerfile
│ ├── requirements.txt
│ ├── main.py
│ ├── 📂 config/
│ │ └── config.py
│ ├── 📂 docs/
│ │ └── swagger.yaml
│ └── 📂 src/
│ ├── 📂 api/
│ │ ├── 📂 atividades/
│ │ │ └── api_atividades.py # Rotas de atividades
│ │ └── 📂 notas/
│ │ └── api_notas.py # Rotas de notas
│ ├── 📂 controllers/
│ │ ├── ctrls_atividades.py # Lógica de negócio (validações HTTP)
│ │ └── ctrls_notas.py
│ └── 📂 models/
│ ├── __init__.py
│ ├── models_atividades.py # Modelo de dados
│ └── models_notas.py
│
├── 📂 gerenciamento/ # Microsserviço de Gerenciamento
│ ├── Dockerfile
│ ├── requirements.txt
│ ├── main.py
│ ├── 📂 config/
│ │ └── config.py
│ ├── 📂 docs/
│ │ └── swagger.yaml
│ └── 📂 src/
│ ├── 📂 api/
│ │ ├── 📂 aluno/
│ │ │ └── api_alunos.py
│ │ ├── 📂 professores/
│ │ │ └── api_professores.py
│ │ └── 📂 turma/
│ │ └── api_turma.py
│ ├── 📂 controllers/
│ │ ├── ctrls_aluno.py
│ │ ├── ctrls_professores.py
│ │ └── ctrls_turma.py
│ └── 📂 models/
│ ├── __init__.py
│ ├── models_aluno.py
│ ├── models_professor.py
│ └── models_turma.py
│
├── 📂 reservas/ # Microsserviço de Reservas
│ ├── Dockerfile
│ ├── requirements.txt
│ ├── main.py
│ ├── 📂 config/
│ │ └── config.py
│ ├── 📂 docs/
│ │ └── swagger.yaml
│ └── 📂 src/
│ ├── 📂 api/
│ │ └── api.py
│ ├── 📂 controllers/
│ │ └── controll.py
│ └── 📂 models/
│ └── models.py
│
├── docker-compose.yml # Orquestração dos microsserviços
└── README.md # Este arquivo
- Docker: Instalar Docker
- Docker Compose: Instalar Docker Compose
git clone https://github.com/Impacta-Projetos/Mvc-Flask.git
cd Mvc-FlaskExecute o comando abaixo na raiz do projeto:
docker-compose up --buildO que acontece:
- Cria 3 containers Docker (gerenciamento, atividades, reservas)
- Instala todas as dependências automaticamente
- Cria uma rede Docker privada
backendpara comunicação - Inicializa os bancos de dados SQLite
- Expõe as portas 5000, 5001 e 5002
Aguarde até ver as mensagens:
gerenciamento | * Running on http://0.0.0.0:5000
atividades | * Running on http://0.0.0.0:5001
reservas | * Running on http://0.0.0.0:5002
- Gerenciamento: http://localhost:5000/apidocs
- Atividades: http://localhost:5001/apidocs
- Reservas: http://localhost:5002/apidocs
curl -X POST http://localhost:5000/professores \
-H "Content-Type: application/json" \
-d '{
"nome": "Dr. João Silva",
"idade": 45,
"materia": "Matemática",
"observacoes": "Professor titular"
}'Resposta esperada:
{
"mensagem": "Professor criado com sucesso."
}curl -X POST http://localhost:5000/turmas \
-H "Content-Type: application/json" \
-d '{
"nome": "Turma 3A",
"professor_id": 1,
"ativo": true
}'Esta requisição vai validar automaticamente se o professor e a turma existem fazendo requisições HTTP ao microsserviço de Gerenciamento:
curl -X POST http://localhost:5001/atividades \
-H "Content-Type: application/json" \
-d '{
"descricao": "Prova de Cálculo 1",
"data_entrega": "2025-12-15",
"turma_id": 1,
"professor_id": 1
}'Se o professor ou turma não existirem, você receberá:
{
"erro": "Professor não encontrado. Status: 404"
}Se ambos existirem:
{
"mensagem": "Atividade criada com sucesso."
}docker-compose downPara também remover os volumes (bancos de dados):
docker-compose down -vPara debugar problemas de comunicação:
# Ver logs de todos os serviços
docker-compose logs
# Ver logs de um serviço específico
docker-compose logs atividades
docker-compose logs gerenciamento
# Ver logs em tempo real
docker-compose logs -fCada microsserviço possui sua documentação Swagger interativa:
- Gerenciamento: http://localhost:5000/apidocs
- Atividades: http://localhost:5001/apidocs
- Reservas: http://localhost:5002/apidocs
| Método | Endpoint | Descrição |
|---|---|---|
| GET | /professores |
Lista todos os professores |
| GET | /professores/{id} |
Busca um professor específico |
| POST | /professores |
Cria um novo professor |
| PUT | /professores/{id} |
Atualiza um professor |
| DELETE | /professores/{id} |
Remove um professor |
Exemplo de Criação:
POST /professores
{
"nome": "Dr. João Silva",
"idade": 45,
"materia": "Matemática",
"observacoes": "Professor titular"
}| Método | Endpoint | Descrição |
|---|---|---|
| GET | /turmas |
Lista todas as turmas |
| GET | /turmas/{id} |
Busca uma turma específica |
| POST | /turmas |
Cria uma nova turma |
| PUT | /turmas/{id} |
Atualiza uma turma |
| DELETE | /turmas/{id} |
Remove uma turma |
Exemplo de Criação:
POST /turmas
{
"descricao": "Turma 3A",
"professor_id": 1,
"ativo": true
}| Método | Endpoint | Descrição |
|---|---|---|
| GET | /alunos |
Lista todos os alunos |
| GET | /alunos/{id} |
Busca um aluno específico |
| POST | /alunos |
Cria um novo aluno |
| PUT | /alunos/{id} |
Atualiza um aluno |
| DELETE | /alunos/{id} |
Remove um aluno |
Exemplo de Criação:
POST /alunos
{
"nome": "Maria Santos",
"idade": 16,
"turma_id": 1,
"data_nascimento": "2008-05-15"
}| Método | Endpoint | Descrição |
|---|---|---|
| GET | /atividades |
Lista todas as atividades |
| GET | /atividades/{id} |
Busca uma atividade específica |
| POST | /atividades |
Cria uma nova atividade (valida professor e turma) |
| PUT | /atividades/{id} |
Atualiza uma atividade |
| DELETE | /atividades/{id} |
Remove uma atividade |
Exemplo de Criação (com validação HTTP):
POST /atividades
{
"nome_atividade": "Prova de Cálculo",
"descricao": "Prova de Cálculo 1",
"peso_porcento": 30,
"data_entrega": "2025-12-15",
"turma_id": 1,
"professor_id": 1
}Validações realizadas automaticamente:
- Consulta
GET http://gerenciamento:5000/professores/1 - Consulta
GET http://gerenciamento:5000/turmas/1 - Só cria a atividade se ambos existirem
| Método | Endpoint | Descrição |
|---|---|---|
| GET | /notas |
Lista todas as notas |
| GET | /notas/{id} |
Busca uma nota específica |
| POST | /notas |
Cria uma nova nota (valida aluno) |
| PUT | /notas/{id} |
Atualiza uma nota |
| DELETE | /notas/{id} |
Remove uma nota |
Exemplo de Criação (com validação HTTP):
POST /notas
{
"nota": 9.5,
"aluno_id": 1,
"atividade_id": 1
}Validação realizada automaticamente:
- Consulta
GET http://gerenciamento:5000/alunos/1 - Só cria a nota se o aluno existir
| Método | Endpoint | Descrição |
|---|---|---|
| GET | /reservas |
Lista todas as reservas |
| GET | /reservas/{id} |
Busca uma reserva específica |
| POST | /reservas |
Cria uma nova reserva |
| PUT | /reservas/{id} |
Atualiza uma reserva |
| DELETE | /reservas/{id} |
Remove uma reserva |
Exemplo de Criação (com validação HTTP):
POST /reservas
{
"num_sala": 205,
"lab": true,
"data": "2025-12-15",
"turma_id": 1
}Validações realizadas automaticamente:
- Consulta
GET http://gerenciamento:5000/turmas/1 - Só cria a reserva se a turma existir
# 1. Criar um professor
curl -X POST http://localhost:5000/professores \
-H "Content-Type: application/json" \
-d '{"nome": "Prof. Ana", "idade": 40, "materia": "História", "observacoes": ""}'
# 2. Criar uma turma
curl -X POST http://localhost:5000/turmas \
-H "Content-Type: application/json" \
-d '{"nome": "Turma 2B", "professor_id": 1, "ativo": true}'
# 3. Criar uma atividade (valida professor e turma via HTTP)
curl -X POST http://localhost:5001/atividades \
-H "Content-Type: application/json" \
-d '{"descricao": "Trabalho de História", "data_entrega": "2025-11-30", "turma_id": 1, "professor_id": 1}'
# Resposta: {"mensagem": "Atividade criada com sucesso."}# Tentar criar atividade com professor inexistente
curl -X POST http://localhost:5001/atividades \
-H "Content-Type: application/json" \
-d '{"descricao": "Atividade Teste", "data_entrega": "2025-12-01", "turma_id": 1, "professor_id": 999}'
# Resposta: {"erro": "Professor não encontrado. Status: 404"}# Parar o microsserviço de gerenciamento
docker-compose stop gerenciamento
# Tentar criar atividade
curl -X POST http://localhost:5001/atividades \
-H "Content-Type: application/json" \
-d '{"descricao": "Teste", "data_entrega": "2025-12-01", "turma_id": 1, "professor_id": 1}'
# Resposta: {"erro": "Erro de conexão com Gerenciamento: ..."}Se preferir executar sem Docker para desenvolvimento:
# Gerenciamento
cd gerenciamento
pip install -r requirements.txt
python main.py
# Atividades (em outro terminal)
cd atividades
pip install -r requirements.txt
python main.py
# Reservas (em outro terminal)
cd reservas
pip install -r requirements.txt
python main.pyQuando executar localmente sem Docker, edite os controllers para usar localhost ao invés dos nomes dos containers:
# Em ctrls_atividades.py
response = requests.get(f'http://localhost:5000/professores/{professor_id}')Professor
{
"id": 1,
"nome": "Dr. João Silva",
"idade": 45,
"materia": "Matemática",
"observacoes": "Professor titular"
}Turma
{
"id": 1,
"descricao": "Turma 3A",
"professor_id": 1,
"ativo": true
}Aluno
{
"id": 1,
"nome": "Maria Santos",
"idade": 16,
"turma_id": 1,
"data_nascimento": "2008-05-15"
}Atividade
{
"id": 1,
"descricao": "Prova de Cálculo 1",
"data_entrega": "2025-12-15",
"turma_id": 1, # Referência ao microsserviço de Gerenciamento
"professor_id": 1 # Referência ao microsserviço de Gerenciamento
}Nota
{
"id": 1,
"nota": 9.5,
"aluno_id": 1, # Referência ao microsserviço de Gerenciamento
"atividade_id": 1
}Reserva
{
"id": 1,
"num_sala": "203",
"lab": true,
"data_reserva": "2025-11-15",
"turma_id": 1 # Referência ao microsserviço de Gerenciamento
}Causa: O microsserviço de Gerenciamento não está acessível.
Solução:
# Verificar se todos os containers estão rodando
docker-compose ps
# Ver logs do serviço
docker-compose logs gerenciamento
# Reiniciar os serviços
docker-compose restartCausa: O professor_id fornecido não existe no banco de dados do microsserviço de Gerenciamento.
Solução:
- Listar professores:
curl http://localhost:5000/professores - Criar o professor se necessário
- Usar um ID válido ao criar a atividade
Causa: Containers não estão na mesma rede Docker ou foram iniciados individualmente.
Solução:
# Sempre usar docker-compose
docker-compose down
docker-compose up --buildArquitetura de Microsserviços: Serviços independentes e desacoplados
Padrão MVC: Separação clara de responsabilidades
RESTful API: Endpoints seguindo convenções REST
Validação Cross-Service: Validações via HTTP entre microsserviços
Tratamento de Erros: Respostas apropriadas para cada cenário
Documentação Swagger: Documentação interativa automática
Containerização: Deploy consistente com Docker
Bancos Independentes: Cada microsserviço com seu próprio banco
Códigos de Status HTTP: Uso correto de status codes (200, 201, 404, 400, etc.)
version: '3.8'
services:
atividades:
build: ./atividades
ports:
- "5001:5001"
volumes:
- ./atividades:/app
networks:
- backend
container_name: atividades
gerenciamento:
build: ./gerenciamento
ports:
- "5000:5000"
volumes:
- ./gerenciamento:/app
networks:
- backend
container_name: gerenciamento
reservas:
build: ./reservas
ports:
- "5002:5002"
volumes:
- ./reservas:/app
networks:
- backend
container_name: reservas
networks:
backend:
driver: bridgeFROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "main.py"]Desenvolvido como projeto acadêmico para a disciplina de Desenvolvimento de APIs.
Equipe:
- Felipe Viana
- Iago Rozales
- Ryan Rodrigues
Instituição: Faculdade Impacta
Curso: Análise e Desenvolvimento de Sistemas
Ano: 2025
- Flask Documentation
- SQLAlchemy Documentation
- Docker Documentation
- RESTful API Design
- Microservices Architecture
Se este projeto foi útil para você, deixe uma star no repositório!