Flask и React — от нуля до Full Stack проекта (с примерами)

Flask и React — от нуля до Full Stack проекта (с примерами)


В данной статье вы узнаете, как использовать Flask и React для создания full-stack приложений, которые легко масштабируются.

В этой архитектуре React обрабатывает пользовательский интерфейс (UI) и взаимодействует с Flask отдельно от бэкенда, используя безопасные запросы. Чтобы сделать эту статью более полезной, мы упомянем несколько проектов с открытым исходным кодом, доступных для скачивания с Github по лицензии MIT.

На заметку: Все ресурсы из данной статьи доступны для загрузки с Github. Админ-Панель на React настроена для работы с простым Flask API Server.

Обзор проекта, созданного с помощью Flask и React

Full-stack проекты могут быть структурированы с помощью различных способов и паттернов. Ниже будут представлены два наиболее популярных паттерна:

Бэкенд + SPA (одностраничное приложение) — в этой конфигурации бэкенд Flask построен по старому доброму паттерну MVC, где файлы обслуживаются из бэкенда, а приложение React обеспечивает взаимодействие с пользователями. Данная модель, была когда-то очень популярна, но уже забыта, потому что из-за смешанного характера технологий их было трудно расширить.

Двухуровневая архитектура — этот паттерн функционально и физически отделяет пользовательский интерфейс (UI) React от бэкенда Flask и использует мост связи через API, предоставляемый сервером. Эта конструкция имеет несколько преимуществ по сравнению с предыдущим решением:

  • Пользовательский интерфейс (UI) и бэкэнд можно разрабатывать и тестировать как отдельные объекты;
  • Более простое развертывание, или деплоймент;
  • При необходимости пользовательский интерфейс (UI) может использовать тестовый API бэкенда (например если готовится новая версия).

Эта статья будет посвящена второму паттерну, двухуровневой архитектуре, где Flask API отделен от React UI.

Далее представлен примерный поток проекта:

  • Запускается сервер Flask и открывается API;
  • React UI загружается в браузер пользователя;
  • React инициирует вход в систему и получает учетные данные, предоставленные пользователем;
  • React отправляет учетные данные пользователя на API сервер;
  • Flask API проверяет учетные данные и генерирует JWT токен;
  • React UI сохраняет информацию о пользователе и его JWT токен;
  • Доступ к админке предоставляется до тех пор, пока пользователь не выйдет из системы.

Требования для Flask + React проекта

Для успешной сборки нашего full-stack проекта, несколько инструментов и библиотек должны быть уже установлены и доступны в терминале.

  • GIT — инструмент командной строки для управления версиями;
  • Python 3 — язык программирования, на котором работает Flask;
  • Node JS — используется для привлечения в наш мир магии React;
  • Yarn — используется для установки Node JS пакетов;
  • Современный редактор кода. К примеру, VsCode или PyCharm;
  • Возможность работать в терминале и писать системные команды;
  • PIP (поставляется с Python3) — используется для установки пакетов Python.

Что такое Flask?

Flask — это популярный веб-фреймворк для Python, предназначенный для быстрого и простого создания проекта с возможностью масштабирования до сложных приложений. Flask можно использовать при создании простых одностраничных сайтов, а также при разработке API и сложных проектов для электронной коммерции.

Используя Flask, разработчик может свободно структурировать кодовую базу без ограничений, а также устанавливать только те библиотеки, которые он действительно использует. Самый простой способ установить Flask это использовать PIP, официальный менеджер пакетов, поставляемый вместе с Python.

Shell

Во время инсталляции также устанавливается базовый набор основных зависимостей которые нужны в Flask:

  • Werkzeug — имплементирует WSGI, стандартный интерфейс Python между приложениями и серверами;
  • Jinja — это язык шаблонов, который делает рендеринг страниц для обслуживаемых приложением;
  • MarkupSafe поставляется вместе с Jinja. Он экранирует подозрительный ввод данных от пользователя при рендеринге шаблонов, чтобы избежать SQL-инъекций или XSS атак;
  • ItsDangerous — надежно подписывает данные для обеспечения их целостности. Это используется для защиты куки сессии в Flask;
  • Click — это фреймворк для написания приложений командной строки.


Что такое React?

В 2021 году статистика показывает, что React используется в качестве основной технологии при разработке фронтенда, вытесняя другие фреймворки, такие как VueAngular или SvelteReact активно поддерживается и развивается силами Facebook, а также широко используется крупными компаниями, многими разработчиками и open-source энтузиастами.

React можно использовать в старых проектах через импорт из CDN или начать новый проект с помощью инструмента командной строки CRA (create-react-app). В нашем примере мы будем использовать шаблон с открытым исходным кодом, в котором код для аутентификации добавлен поверх существующего проекта, изначально созданного с помощью инструмента CRA. Для получения дополнительной информации о React, пожалуйста можете ознакомиться со следующими ресурсами:

Создание бэкенда для Flask API

Flask отлично подходит для написания чего-то полезного за небольшой промежуток времени. Наш бэкенд-сервер должен предоставлять простую службу аутентификации с использованием веб токенов JWT, которая предоставляет несколько основных методов:

  • /api/users/register: создание нового пользователя;
  • /api/users/login: аутентификация существующего пользователя;
  • /api/users/logout: выход пользователя из системы;
  • /api/users/edit: редактирование информации, связанной с зарегистрированным пользователем.

Учитывая эти API требования, следует уточнить некоторые другие аспекты: тип базы данных, используемые библиотеки REST и JWT, и, конечно, структуру проекта. Чтобы облегчить процесс, мы выберем SQLite, но у нас будет возможность миграции на более сложные СУБД, такие как MySQL и PostgreSQL.

Зависимости Flask API

  • flask-restx — используется для маршрутизации API;
  • Flask-JWT-Extended — управление JWT токенами;
  • Flask-SQLAlchemy — абстрактный интерфейс для базы данных.

Мы будем использовать паттерн app factory, где функциональность API изолирована в отдельной папке и построена как Python пакет. Возможная структура проекта показана ниже:

Shell

...

rest_api = Api(version="1.0", title="Users API")

...

Routes.py — Инициализация валидатора для проверки данных из формы регистрации.

Routes.py - Определение валидации (пример SignUp)

1

2

3

4

5

6

7

signup_model = rest_api.model(

    'SignUpModel', {

        "username": fields.String(required=True, min_length=2, max_length=32),

        "email": fields.String(required=True, min_length=4, max_length=64),

        "password": fields.String(required=True, min_length=4, max_length=16)

    }

)

Routes.py - Код обработчика API регистрации

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

@rest_api.route('/api/users/register')

class Register(Resource):

    """

      Регистрация нового пользователя в базе данных с использованием подели `signup_model`.

    """

    @rest_api.expect(signup_model, validate=True)

    def post(self):

        req_data = request.get_json()

        _username = req_data.get("username")

        _email = req_data.get("email")

        _password = req_data.get("password")

        user_exists = Users.get_by_email(_email)

        if user_exists:

            return {"success": False,

                    "msg": "Email already taken"}, 400

        new_user = Users(username=_username, email=_email)

        new_user.set_password(_password)

        new_user.save()

        return {

            "success": True,

            "userID": new_user.id,

            "msg": "Пользователь успешно зарегистрирован"

        }, 200

Приведенные выше фрагменты кода (валидатор, обработчик данных) должны быть повторены для всех методов API.

Финальный код Routes.py:

from flask_restx import Api, Resource, fields

import jwt

from .models import db, Users

rest_api = Api(version="1.0", title="Users API")

signup_model = rest_api.model(

    'SignUpModel', {

        "username": fields.String(required=True, min_length=2, max_length=32),

        "email": fields.String(required=True, min_length=4, max_length=64),

        "password": fields.String(required=True, min_length=4, max_length=16)

    }

)

@rest_api.route('/api/users/register')

class Register(Resource):

    """

      Регистрация нового пользователя в базе данных с использованием подели `signup_model`.

    """

    @rest_api.expect(signup_model, validate=True)

    def post(self):

        req_data = request.get_json()

        _username = req_data.get("username")

        _email = req_data.get("email")

        _password = req_data.get("password")

        user_exists = Users.get_by_email(_email)

        if user_exists:

            return {"success": False,

                    "msg": "Email already taken"}, 400

        new_user = Users(username=_username, email=_email)

        new_user.set_password(_password)

        new_user.save()

        return {

            "success": True,

            "userID": new_user.id,

            "msg": "Пользователь успешно зарегистрирован"

        }, 200

Тестирование Flask API с помощью POSTMAN

Когда API запущен и работает, мы можем использовать POSTMAN, это популярный и бесплатный инструмент для тестирования точек входа от API. Мы предполагаем, что Flask API запущен на порту 5000, а метод регистрации полностью прописан и работает.

Postman — Создаем запрос со следующими свойствами:

  • POST-запрос по адресу "http://localhost:5000/api/users/register"
  • Заголовок Content-type"application-json"
  • Тело запроса (данные пользователя для регистрации): user/password и email

Содержимое из тела запроса предоставляет данные для регистрации нового пользователя.

Полученный ответ от API после регистрации.

На этом этапе пользователь уже создан в базе данных, и мы можем пройти аутентификацию и продолжить работу над нашим full-stack проектом.

React UI — Пользовательский интерфейс

React часть этого руководства написана поверх проекта с открытым исходным кодом, клонированного с Github, а именно React Datta Able, которая является действительно красивой и красочной Панели-Управления, предоставленной студией CodedThemes.

Первоначальный проект это по сути React шаблон, который будет улучшен с помощью нескольких простых особенностей:

  • Удобный процесс аутентификации пользователя, совместимый с Flask API;
  • Возможности: Входа, Выхода и Регистрации;
  • Неавторизованные пользователи будут перенаправлены на страницу входа в систему;
  • Панель-управления видна только аутентифицированным пользователям.

Проект имеет действительно красивый дизайн. Давайте загрузим готовую сборку этого React шаблона и позже добавим необходимый код для расширения всего функционала.

Shell

Чтобы создать новый функционал, сперва необходимо обновить зависимости проекта, добавив несколько полезных библиотек:

  • Formik — используется для управления формами регистрации;
  • Axios — используется для коммуникации между браузером пользователя и API.

Как только новые зависимости будут правильно установлены, мы сможем продолжить работу над кодом.

Найстройка проекта — API точки входа

Приложение будет использовать общий набор переменных, импортируемых в различные места, такие как страница аутентификации, выход пользователя и т.д.

Для упрощения это процесса — было бы неплохо определить все переменные в одном файле: src/config/constant.js

1

2

3

4

export const BASENAME = ''; // не добавляйте '/' в конце BASENAME

export const BASE_URL = '/app/dashboard/default';

export const BASE_TITLE = ' | React Datta Able ';

export const API_SERVER = 'http://localhost:5000/api/';

Наиболее важное значение сохраняет переменная API_SERVER, по сути это адрес нашего API. Когда проект будет запущен в рабочем режиме, то этот адрес должен быть обновлен соответствующим образом с адресом публичного API который будет содержать нормальный домен.

Создание компонента Guest Guard (Гостевой охранник)

Этот компонент отвечает за определение того, аутентифицирован ли текущий пользователь или нет. Простые гости перенаправляются на страницу входа, а аутентифицированные пользователи получают доступ ко всем приватным страницам.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

import React from 'react';

import { Redirect } from 'react-router-dom';

import { useSelector } from 'react-redux';

import { BASE_URL } from '../../config/constant';

const GuestGuard = ({ children }) => {

    const account = useSelector((state) => state.account);

    const { isLoggedIn } = account;

    if (isLoggedIn) {

        return <Redirect to={BASE_URL} />;

    }

    return <React.Fragment>{children}</React.Fragment>;

};

export default GuestGuard;


Создаем Redux-хранилище, управляющее состоянием пользователя

Приложение React должно быть способно принимать решения на основе информации, связанной с текущим пользователем. Хранилище redux-store предоставляет эту информацию простым способом, используя несколько переменных и объектов:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

export const initialState = {

    token: '',

    isLoggedIn: false,

    isInitialized: false,

    user: null

};

const accountReducer = (state = initialState, action) => {

    switch (action.type) {

        case ACCOUNT_INITIALIZE: {

            const { isLoggedIn, user, token } = action.payload;

            return {

                ...state,

                isLoggedIn,

                isInitialized: true,

                token,

                user

            };

        }

        case LOGIN: {

            const { user } = action.payload;

            return {

                ...state,

                isLoggedIn: true,

                user

            };

        }

        case LOGOUT: {

            return {

                ...state,

                isLoggedIn: false,

                token: '',

                user: null

            };

        }

        default: {

            return { ...state };

        }

    }

};

Переменные, связанные с текущим пользователем, должны обновляться на основе действий, выполняемых в сессии:

  • Гостевой доступ: пользовательская сессия не существует — Null, состояние переменной isLoggedIn равно false;
  • Вход: пользователь успешно прошел аутентификацию. Содержимое переменной isLoggedIn становится true;
  • Выход: все данные сессии удаляются, и содержимое переменной isLoggedIn снова становится false.

На данном этапе — React UI можно использовать для регистрации и аутентификации пользователей.



Report Page