JavaRush /Курси /Модуль 2: Fullstack /Проєктування архітектури застосунку

Проєктування архітектури застосунку

Модуль 2: Fullstack
Рівень 18 , Лекція 1
Відкрита

2.1 Загальна архітектура

На цьому етапі ми спроєктуємо архітектуру застосунку для управління задачами. Ми визначимо, як буде взаємодіяти frontend, backend і база даних, а також які компоненти увійдуть у кожен із них.

Застосунок складатиметься з трьох основних компонентів:

  • Frontend (ReactJS): клієнтська частина, що забезпечує взаємодію користувача із системою.
  • Backend (Flask): серверна частина, яка обробляє запити від фронтенду і взаємодіє з базою даних.
  • Database (PostgreSQL): сховище даних для користувачів і задач.

Архітектура виглядатиме наступним чином:

Термінал

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

Взаємодія між компонентами

  • Frontend: відправляє HTTP-запити до бекенду для виконання CRUD-операцій (створення, читання, оновлення, видалення задач).
  • Backend: обробляє HTTP-запити від фронтенду, виконує бізнес-логіку і взаємодіє з базою даних.
  • Database: зберігає та надає дані за запитами від бекенду.

2.2 Опис кожного компонента

1. Frontend (ReactJS):

  • Компоненти інтерфейсу: компоненти для реєстрації та авторизації користувачів, створення й редагування завдань, перегляду списку завдань.
  • Взаємодія з API: використання бібліотеки Axios для відправки HTTP-запитів до бекенду.

2. Backend (Flask):

  • REST API: реалізація ендпоінтів для управління користувачами та завданнями.
  • Моделі даних: визначення моделей даних для користувачів і завдань з використанням SQLAlchemy.
  • Бізнес-логіка: обробка логіки застосунку, включаючи валідацію даних та управління сесіями користувачів.

3. Database (PostgreSQL):

  • Таблиці: таблиці для зберігання інформації про користувачів і завдання.
  • Зв’язки між таблицями: визначення зв'язків між таблицями користувачів і завдань (наприклад, один користувач може мати багато завдань).

4. Мережна взаємодія

Уся комунікація між компонентами відбуватиметься через HTTP-протокол. Фронтенд буде взаємодіяти з бекендом через REST API, а бекенд — з базою даних через SQL-запити.

  • Frontend: порт 3000 для розробки та тестування.
  • Backend: порт 5000 для взаємодії з фронтендом.
  • Database: порт 5432 для взаємодії з бекендом.

2.3 Детальний опис кожного компонента

1. Базова структура даних

Для зберігання даних про користувачів і задачі у базі даних PostgreSQL створимо дві таблиці: users і tasks.

Таблиця users:

  • id (int, primary key): унікальний ідентифікатор користувача.
  • username (varchar, unique): ім'я користувача.
  • password (varchar): хеш пароля користувача.

Таблиця tasks:

  • id (int, primary key): унікальний ідентифікатор задачі.
  • title (varchar): заголовок задачі.
  • description (text): опис задачі.
  • owner_id (int, foreign key): ідентифікатор користувача, якому призначена задача.
  • status (varchar): статус задачі (наприклад, виконана/невиконана).

2. API дизайн

Бекенд надаватиме RESTful API для взаємодії із фронтендом. Приблизний список ендпоінтів:

  • Користувачі:
    • POST /users: створення нового користувача.
    • GET /users: отримання списку всіх користувачів.
    • GET /users/:id: отримання інформації про конкретного користувача.
    • PUT /users/:id: оновлення інформації про користувача.
    • DELETE /users/:id: видалення користувача.
  • Задачі:
    • POST /tasks: створення нової задачі.
    • GET /tasks: отримання списку всіх задач.
    • GET /tasks/:id: отримання інформації про конкретну задачу.
    • PUT /tasks/:id: оновлення інформації про задачу.
    • DELETE /tasks/:id: видалення задачі.

2.4 Моделі даних

Ось як виглядатиме код на Python для роботи з таблицями бази даних:

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="невиконана")
    def to_dict(self):
        return {
            "id": self.id,
            "title": self.title,
            "description": self.description,
            "owner_id": self.owner_id,
            "status": self.status
        }

2.5 Маршрути і контролери

Приклад реалізації API на стороні сервера:

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', "невиконана")
    )
    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 Приклад звернення до сервера з боку фронтенда

Приклад компонента React для відображення списку задач:

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('Сталася помилка під час отримання задач!', error);
      });
  }, []);

  return (
    <div>
      <h1>Список задач</h1>
      <ul>
        {tasks.map(task => (
          <li key={task.id}>{task.title} - {task.status}</li>
        ))}
      </ul>
    </div>
  );
};

export default TaskList;
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ