CodeGym /Các khóa học /Docker SELF /Thiết kế kiến trúc ứng dụng

Thiết kế kiến trúc ứng dụng

Docker SELF
Mức độ , Bài học
Có sẵn

2.1 Kiến trúc chung

Ở bước này, chúng ta sẽ thiết kế kiến trúc ứng dụng để quản lý các task. Chúng ta sẽ xác định cách frontend, backend và database tương tác với nhau cũng như các thành phần nào sẽ được bao gồm trong từng phần.

Ứng dụng sẽ bao gồm ba thành phần chính:

  • Frontend (ReactJS): phần phía client, cung cấp giao diện để người dùng tương tác với hệ thống.
  • Backend (Flask): phần phía server, xử lý các request từ frontend và tương tác với database.
  • Database (PostgreSQL): nơi lưu trữ dữ liệu cho thông tin người dùng và các task.

Kiến trúc sẽ được biểu diễn như sau:

Terminal

+-------------+       +-------------+       +--------------+
|             |       |             |       |              |
|  Frontend   +------->+   Backend   +------->+   Database   |
|  (ReactJS)  |       |   (Flask)   |       | (PostgreSQL) |
|             |       |             |       |              |
+-------------+       +-------------+       +--------------+

Tương tác giữa các thành phần

  • Frontend: gửi HTTP-request tới backend để thực hiện các thao tác CRUD (tạo, đọc, cập nhật, xóa task).
  • Backend: xử lý các HTTP-request từ frontend, thực hiện business logic và tương tác với database.
  • Database: lưu trữ và cung cấp dữ liệu theo các request từ backend.

2.2 Mô tả từng thành phần

1. Frontend (ReactJS):

  • Thành phần giao diện: các thành phần để đăng ký và đăng nhập người dùng, tạo và chỉnh sửa nhiệm vụ, xem danh sách nhiệm vụ.
  • Tương tác với API: sử dụng thư viện Axios để gửi các yêu cầu HTTP đến backend.

2. Backend (Flask):

  • REST API: triển khai các endpoint để quản lý người dùng và nhiệm vụ.
  • Mô hình dữ liệu: định nghĩa các mô hình dữ liệu cho người dùng và nhiệm vụ bằng cách sử dụng SQLAlchemy.
  • Logic nghiệp vụ: xử lý logic ứng dụng bao gồm xác thực dữ liệu và quản lý phiên người dùng.

3. Database (PostgreSQL):

  • Bảng: các bảng để lưu trữ thông tin về người dùng và nhiệm vụ.
  • Mối quan hệ giữa các bảng: định nghĩa mối quan hệ giữa bảng người dùng và bảng nhiệm vụ (ví dụ: một người dùng có thể có nhiều nhiệm vụ).

4. Tương tác mạng

Mọi giao tiếp giữa các thành phần sẽ diễn ra thông qua giao thức HTTP. Frontend sẽ tương tác với backend qua REST API, và backend sẽ tương tác với cơ sở dữ liệu qua truy vấn SQL.

  • Frontend: cổng 3000 cho phát triển và kiểm thử.
  • Backend: cổng 5000 để tương tác với frontend.
  • Database: cổng 5432 để tương tác với backend.

2.3 Mô tả chi tiết từng thành phần

1. Cấu trúc dữ liệu cơ bản

Để lưu trữ dữ liệu về người dùng và nhiệm vụ trong cơ sở dữ liệu PostgreSQL, chúng mình sẽ tạo hai bảng: userstasks.

Bảng users:

  • id (int, primary key): định danh duy nhất cho người dùng.
  • username (varchar, unique): tên người dùng.
  • password (varchar): hash mật khẩu của người dùng.

Bảng tasks:

  • id (int, primary key): định danh duy nhất cho nhiệm vụ.
  • title (varchar): tiêu đề của nhiệm vụ.
  • description (text): mô tả về nhiệm vụ.
  • owner_id (int, foreign key): định danh của người dùng mà nhiệm vụ được giao.
  • status (varchar): trạng thái của nhiệm vụ (ví dụ: hoàn thành/chưa hoàn thành).

2. Thiết kế API

Backend sẽ cung cấp RESTful API để giao tiếp với frontend. Danh sách các endpoint dự kiến là:

  • Người dùng:
    • POST /users: tạo người dùng mới.
    • GET /users: lấy danh sách tất cả người dùng.
    • GET /users/:id: lấy thông tin về một người dùng cụ thể.
    • PUT /users/:id: cập nhật thông tin người dùng.
    • DELETE /users/:id: xóa người dùng.
  • Nhiệm vụ:
    • POST /tasks: tạo nhiệm vụ mới.
    • GET /tasks: lấy danh sách tất cả nhiệm vụ.
    • GET /tasks/:id: lấy thông tin về một nhiệm vụ cụ thể.
    • PUT /tasks/:id: cập nhật thông tin nhiệm vụ.
    • DELETE /tasks/:id: xóa nhiệm vụ.

2.4 Mô hình dữ liệu

Đây là cách code Python để làm việc với bảng cơ sở dữ liệu sẽ trông như thế nào:

User Model:

Python

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:

Python

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="chưa hoàn thành")
    def to_dict(self):
        return {
            "id": self.id,
            "title": self.title,
            "description": self.description,
            "owner_id": self.owner_id,
            "status": self.status
        }

2.5 Router và Controller

Ví dụ triển khai API phía server:

Python

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', "chưa hoàn thành")
    )
    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 Ví dụ gọi server từ frontend

Ví dụ component React để hiển thị danh sách công việc:

Javascript

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('Đã xảy ra lỗi khi lấy dữ liệu tasks!', error);
      });
  }, []);

  return (
    <div>
      <h1>Danh sách công việc</h1>
      <ul>
        {tasks.map(task => (
          <li key={task.id}>{task.title} - {task.status}</li>
        ))}
      </ul>
    </div>
  );
};

export default TaskList;
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION