2.1 General Architecture
At this stage, we’ll design the application architecture for task management. We’ll define how the frontend, backend, and database will interact, as well as which components will be included in each of them.
The application will consist of three main components:
- Frontend (ReactJS): the client-side part responsible for user interaction with the system.
- Backend (Flask): the server-side part that processes requests from the frontend and interacts with the database.
- Database (PostgreSQL): the data storage for users and tasks.
The architecture will look like this:
+-------------+ +-------------+ +--------------+
| | | | | |
| Frontend +------->+ Backend +------->+ Database |
| (ReactJS) | | (Flask) | | (PostgreSQL) |
| | | | | |
+-------------+ +-------------+ +--------------+
Interaction Between Components
- Frontend: sends HTTP requests to the backend to perform CRUD operations (create, read, update, delete tasks).
- Backend: processes HTTP requests from the frontend, handles business logic, and interacts with the database.
- Database: stores and provides data based on requests from the backend.
2.2 Description of Each Component
1. Frontend (ReactJS):
- Interface Components: components for user registration and authorization, creating and editing tasks, viewing the task list.
- API Interaction: using the Axios library to send HTTP requests to the backend.
2. Backend (Flask):
- REST API: implementing endpoints for managing users and tasks.
- Data Models: defining data models for users and tasks using SQLAlchemy.
- Business Logic: handling application logic, including data validation and user session management.
3. Database (PostgreSQL):
- Tables: tables for storing information about users and tasks.
- Table Relationships: defining relationships between user and task tables (e.g., one user can have many tasks).
4. Network Interaction
All communication between components will be via the HTTP protocol. The frontend will interact with the backend through the REST API, and the backend will interact with the database using SQL queries.
- Frontend: port 3000 for development and testing.
- Backend: port 5000 for interaction with the frontend.
- Database: port 5432 for interaction with the backend.
2.3 Detailed Description of Each Component
1. Basic Data Structure
To store data about users and tasks in the PostgreSQL database, we will create two tables: users
and tasks
.
Table users
:
-
id (int, primary key)
: unique identifier of the user. username (varchar, unique)
: the username.password (varchar)
: the user's password hash.
Table tasks
:
-
id (int, primary key)
: unique identifier of the task. title (varchar)
: task title.description (text)
: task description.-
owner_id (int, foreign key)
: the ID of the user assigned to the task. -
status (varchar)
: task status (e.g., completed/not completed).
2. API Design
The backend will provide a RESTful API to interact with the frontend. An approximate list of endpoints:
- Users:
- POST /users: create a new user.
- GET /users: get a list of all users.
- GET /users/:id: get information about a specific user.
- PUT /users/:id: update user information.
- DELETE /users/:id: delete a user.
- Tasks:
- POST /tasks: create a new task.
- GET /tasks: get a list of all tasks.
- GET /tasks/:id: get information about a specific task.
- PUT /tasks/:id: update task information.
- DELETE /tasks/:id: delete a task.
2.4 Data Models
Here's what Python code for working with database tables would look like:
User Model:
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
}
Task Model:
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="not completed")
def to_dict(self):
return {
"id": self.id,
"title": self.title,
"description": self.description,
"owner_id": self.owner_id,
"status": self.status
}
2.5 Routes and Controllers
Example of implementing an API on the server side:
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', "not completed")
)
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 Example of a Frontend Request to the Server
An example of a React component for displaying a task list:
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('There was an error fetching the tasks!', error);
});
}, []);
return (
<div>
<h1>Task List</h1>
<ul>
{tasks.map(task => (
<li key={task.id}>{task.title} - {task.status}</li>
))}
</ul>
</div>
);
};
export default TaskList;
GO TO FULL VERSION