2.1 Arquitetura Geral
Nesta etapa, vamos planejar a arquitetura do aplicativo para gerenciamento de tarefas. Vamos definir como o frontend, backend e o banco de dados irão interagir, além de quais componentes estarão incluídos em cada um deles.
O aplicativo será composto por três componentes principais:
- Frontend (ReactJS): Parte do cliente que garante a interação do usuário com o sistema.
- Backend (Flask): Parte do servidor que processa as solicitações do frontend e interage com o banco de dados.
- Database (PostgreSQL): Armazenamento de dados para usuários e tarefas.
A arquitetura terá o seguinte formato:
+-------------+ +-------------+ +--------------+
| | | | | |
| Frontend +------->+ Backend +------->+ Database |
| (ReactJS) | | (Flask) | | (PostgreSQL) |
| | | | | |
+-------------+ +-------------+ +--------------+
Interação entre os componentes
- Frontend: envia requisições HTTP para o backend realizar operações CRUD (criar, ler, atualizar, excluir tarefas).
- Backend: processa as requisições HTTP do frontend, executa a lógica de negócios e interage com o banco de dados.
- Database: armazena e fornece dados mediante solicitações do backend.
2.2 Descrição de cada componente
1. Frontend (ReactJS):
- Componentes de interface: componentes para registro e login de usuários, criação e edição de tarefas, visualização da lista de tarefas.
- Interação com API: uso da biblioteca Axios para enviar requisições HTTP para o backend.
2. Backend (Flask):
- REST API: implementação de endpoints para gerenciamento de usuários e tarefas.
- Modelos de dados: definição de modelos de dados para usuários e tarefas usando SQLAlchemy.
- Lógica de negócio: processamento da lógica do aplicativo, incluindo validação de dados e gerenciamento de sessões de usuários.
3. Banco de Dados (PostgreSQL):
- Tabelas: tabelas para armazenar informações sobre usuários e tarefas.
- Relações entre tabelas: definição de relações entre tabelas de usuários e tarefas (por exemplo, um usuário pode ter várias tarefas).
4. Interação em rede
Toda a comunicação entre os componentes será feita através do protocolo HTTP. O frontend irá interagir com o backend através da REST API, e o backend — com o banco de dados através de consultas SQL.
- Frontend: porta 3000 para desenvolvimento e testes.
- Backend: porta 5000 para interação com o frontend.
- Database: porta 5432 para interação com o backend.
2.3 Descrição Detalhada de Cada Componente
1. Estrutura Básica de Dados
Para armazenar dados sobre usuários e tarefas no banco de dados PostgreSQL, vamos criar duas tabelas: users
e tasks
.
Tabela users
:
-
id (int, primary key)
: identificador único do usuário. username (varchar, unique)
: nome do usuário.password (varchar)
: hash da senha do usuário.
Tabela tasks
:
-
id (int, primary key)
: identificador único da tarefa. title (varchar)
: título da tarefa.description (text)
: descrição da tarefa.-
owner_id (int, foreign key)
: identificador do usuário ao qual a tarefa foi atribuída. -
status (varchar)
: status da tarefa (por exemplo, concluída/não concluída).
2. Design da API
O backend vai fornecer uma RESTful API para interação com o frontend. Lista aproximada de endpoints:
- Usuários:
- POST /users: criar um novo usuário.
- GET /users: obter a lista de todos os usuários.
- GET /users/:id: obter informações sobre um usuário específico.
- PUT /users/:id: atualizar informações de um usuário.
- DELETE /users/:id: deletar um usuário.
- Tarefas:
- POST /tasks: criar uma nova tarefa.
- GET /tasks: obter a lista de todas as tarefas.
- GET /tasks/:id: obter informações sobre uma tarefa específica.
- PUT /tasks/:id: atualizar informações de uma tarefa.
- DELETE /tasks/:id: deletar uma tarefa.
2.4 Modelos de Dados
É assim que o código em Python para trabalhar com tabelas no banco de dados vai ficar:
Modelo User:
from app import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password = db.Column(db.String(120), nullable=False)
tasks = db.relationship('Task', backref='owner', lazy=True)
def to_dict(self):
return {
"id": self.id,
"username": self.username
}
Modelo Task:
from app import db
class Task(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(120), nullable=False)
description = db.Column(db.Text, nullable=True)
owner_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
status = db.Column(db.String(20), nullable=False, default="não feita")
def to_dict(self):
return {
"id": self.id,
"title": self.title,
"description": self.description,
"owner_id": self.owner_id,
"status": self.status
}
2.5 Rotas e controladores
Exemplo de implementação de API no lado do servidor:
from app import app, db
from app.models import Task, User
from flask import request, jsonify
@app.route('/tasks', methods=['GET'])
def get_tasks():
tasks = Task.query.all()
return jsonify([task.to_dict() for task in tasks])
@app.route('/tasks', methods=['POST'])
def create_task():
data = request.get_json()
new_task = Task(
title=data['title'],
description=data.get('description'),
owner_id=data['owner_id'],
status=data.get('status', "não concluída")
)
db.session.add(new_task)
db.session.commit()
return jsonify(new_task.to_dict()), 201
@app.route('/tasks/<int:id>', methods=['GET'])
def get_task(id):
task = Task.query.get_or_404(id)
return jsonify(task.to_dict())
@app.route('/tasks/<int:id>', methods=['PUT'])
def update_task(id):
data = request.get_json()
task = Task.query.get_or_404(id)
task.title = data['title']
task.description = data.get('description')
task.status = data.get('status', task.status)
task.owner_id = data['owner_id']
db.session.commit()
return jsonify(task.to_dict())
@app.route('/tasks/<int:id>', methods=['DELETE'])
def delete_task(id):
task = Task.query.get_or_404(id)
db.session.delete(task)
db.session.commit()
return '', 204
2.6 Exemplo de chamada ao servidor a partir do frontend
Exemplo de componente React para exibir uma lista de tarefas:
import React, { useEffect, useState } from 'react';
import axios from 'axios';
const TaskList = () => {
const [tasks, setTasks] = useState([]);
useEffect(() => {
axios.get('http://localhost:5000/tasks')
.then(response => {
setTasks(response.data);
})
.catch(error => {
console.error('Ocorreu um erro ao buscar as tarefas!', error);
});
}, []);
return (
<div>
<h1>Lista de Tarefas</h1>
<ul>
{tasks.map(task => (
<li key={task.id}>{task.title} - {task.status}</li>
))}
</ul>
</div>
);
};
export default TaskList;
GO TO FULL VERSION