📖 Теория: Flask-проект от структуры до REST API

⚡ Кратко

  • HTTP методы: GET (read), POST (create), PUT (update), DELETE (delete). GET, PUT, DELETE — идемпотентны.
  • REST: stateless, ресурсы по URL, единообразный интерфейс.
  • Config: класс Config → подклассы DevelopmentConfig, ProductionConfig.
  • Blueprint: bp = Blueprint('name', __name__)app.register_blueprint(bp, url_prefix='/...').
  • Application Factory: def create_app(): app = Flask(__name__); db.init_app(app); return app.

1. Описание проекта — Community Pulse

Community Pulse — интерактивная платформа, где анонимные пользователи могут создавать вопросы на общественно значимые темы и получать мнения других участников.

Основные функции

  • Создание вопросов: пользователи формулируют вопросы, на которые можно ответить «согласен» или «не согласен».
  • Ответы на вопросы: просмотр списка вопросов и голосование.
  • Статистика ответов: для каждого вопроса — счётчик согласных и несогласных.

Технологический стек

ТехнологияНазначение
FlaskВеб-сервер, маршрутизация запросов
Flask-SQLAlchemyORM, управление базой данных
Alembic (Flask-Migrate)Управление миграциями БД
PydanticСериализация и валидация данных

2. HTTP методы

HTTP методы — стандартизированные команды, которые клиенты (браузеры, приложения) используют для взаимодействия с сервером. Они определяют тип операции, которую клиент хочет выполнить.

Основные методы (CRUD)

МетодCRUDИдемпотентен?Описание
GET Read Да Получение данных от сервера. Повторный запрос к тому же URL возвращает тот же результат и не изменяет данные.
POST Create Нет Отправка данных для создания нового ресурса. Каждый повторный запрос может создавать новый ресурс.
PUT Update Да Полное обновление существующего ресурса по URL. Повторный запрос с теми же данными не меняет состояние повторно.
PATCH Partial Update Нет* Частичное обновление ресурса — только указанные поля.
DELETE Delete Да Удаление ресурса. После первого удаления повторный запрос имеет тот же эффект — ресурс уже удалён.
Идемпотентность — это свойство операции, при котором её повторное выполнение даёт тот же результат, что и однократное. Например: удалить уже удалённый ресурс = ресурс всё равно отсутствует.

Дополнительные методы

  • HEAD — как GET, но сервер возвращает только заголовки, без тела. Полезно для получения метаданных без загрузки контента.
  • OPTIONS — возвращает список поддерживаемых методов для ресурса. Используется, в том числе, для CORS preflight-запросов.

3. API и RESTful

Что такое API

API (Application Programming Interface) — инструкция для программ, описывающая, как они могут взаимодействовать друг с другом. Аналогия: официант в ресторане — принимает заказ у клиента и передаёт его на кухню; стороны не взаимодействуют напрямую.

API vs Веб-приложение

APIВеб-приложение
Интерфейс взаимодействия между программами ПО для выполнения задач через браузер
Предоставляет методы и точки входа для других программ Состоит из фронтенда (браузер) и бэкенда (сервер)
Может использоваться несколькими приложениями одновременно Может использовать API для внешних сервисов

Пример: Google Maps API используется приложениями для доставки еды, заказа такси и навигации — три разных приложения, один API.

RESTful архитектура

REST (Representational State Transfer) — архитектурный стиль для API, использующий принципы HTTP. Данные представлены как ресурсы, доступные по URL.

Принципы REST

  • Клиент-сервер: разделение позволяет развивать части независимо.
  • Без сохранения состояния (stateless): каждый запрос содержит всю необходимую информацию; сервер не запоминает предыдущие запросы.
  • Кэшируемость: ответы могут кэшироваться, что ускоряет загрузку.
  • Единообразие интерфейса: ресурсы доступны через стандартные методы.
  • Слой системы: система может состоять из нескольких уровней (прокси, балансировщик).

4. Конфигурация Flask-приложения

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

Конфигурационный файл

# config.py
class Config:
    DEBUG = False
    TESTING = False
    SQLALCHEMY_DATABASE_URI = 'sqlite:///community_pulse.db'
    SQLALCHEMY_TRACK_MODIFICATIONS = False

class DevelopmentConfig(Config):
    DEBUG = True

class TestingConfig(Config):
    TESTING = True
    SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'

class ProductionConfig(Config):
    pass  # использует переменные окружения

Загрузка конфигурации из окружения

import os

config_name = os.environ.get('FLASK_ENV', 'development')
config_class = {
    'development': DevelopmentConfig,
    'testing': TestingConfig,
    'production': ProductionConfig,
}.get(config_name, DevelopmentConfig)

app.config.from_object(config_class)
Современная практика: вместо FLASK_ENV в Flask 3.x используйте переменную FLASK_DEBUG=1 или кастомную переменную APP_ENV. Переменная FLASK_ENV устарела в Flask 2.3+. ⚠️ Проверить по документации Flask 3.x

5. Роутинг в Flask

Простой маршрут

from flask import Flask

app = Flask(__name__)

@app.route('/')
def home():
    return "Добро пожаловать в Community Pulse!"

Маршрут с переменными

Переменные указываются в угловых скобках: <тип:имя>.

@app.route('/questions/<int:question_id>')
def show_question(question_id):
    return f"Вопрос с ID {question_id}"

Конвертеры типов

КонвертерЧто принимает
stringЛюбой текст без слэшей (по умолчанию)
intЦелые числа
floatЧисла с плавающей точкой
pathСтроки, включая слэши (файловые пути)
uuidСтроки в формате UUID

HTTP-методы в маршруте

@app.route('/questions', methods=['GET', 'POST'])
def questions():
    if request.method == 'GET':
        # вернуть список вопросов
        pass
    elif request.method == 'POST':
        # создать новый вопрос
        pass

6. Blueprints — модульная организация

Для крупных проектов Flask-приложение делится на модули — Blueprints. Каждый Blueprint отвечает за свою часть функциональности и может разрабатываться независимо.

Создание Blueprint

# app/routers/questions.py

from flask import Blueprint, jsonify, request

questions_bp = Blueprint('questions', __name__)

@questions_bp.route('/')
def list_questions():
    return jsonify({"questions": []})

@questions_bp.route('/', methods=['POST'])
def add_question():
    data = request.get_json()
    return jsonify({"created": data}), 201

Регистрация Blueprint с url_prefix

# app/__init__.py

from flask import Flask
from app.routers.questions import questions_bp
from app.routers.responses import responses_bp

def create_app():
    app = Flask(__name__)
    app.register_blueprint(questions_bp, url_prefix='/questions')
    app.register_blueprint(responses_bp, url_prefix='/responses')
    return app

Результат: GET /questions/ вызывает list_questions, POST /questions/ вызывает add_question.

Преимущества Blueprints

  • Модульность: каждый Blueprint разрабатывается и тестируется независимо.
  • Масштабируемость: большое приложение легко разделить на компоненты.
  • Повторное использование: Blueprint можно подключить к нескольким приложениям.

7. Application Factory Pattern

Вместо создания объекта app на уровне модуля — использование фабричной функции create_app(). Это современная практика для масштабируемых Flask-приложений.

# app/__init__.py

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()  # расширение создаётся БЕЗ привязки к app

def create_app(config_name='development'):
    app = Flask(__name__)

    # загрузка конфигурации
    from config import config_map
    app.config.from_object(config_map[config_name])

    # инициализация расширений
    db.init_app(app)  # привязка к конкретному app

    # регистрация blueprints
    from app.routers.questions import questions_bp
    from app.routers.responses import responses_bp
    app.register_blueprint(questions_bp, url_prefix='/questions')
    app.register_blueprint(responses_bp, url_prefix='/responses')

    return app
# run.py
from app import create_app

app = create_app()

if __name__ == '__main__':
    app.run()

8. Структура проекта Community Pulse

/community_pulse/
|-- app/
|   |-- __init__.py        # create_app(), инициализация db
|   |-- routers/
|   |   |-- __init__.py
|   |   |-- questions.py   # Blueprint для /questions
|   |   |-- responses.py   # Blueprint для /responses
|   |-- models/
|   |   |-- __init__.py
|   |   |-- questions.py   # Модель Question
|   |   |-- responses.py   # Модель Response
|   |-- schemas/
|       |-- __init__.py
|       |-- question.py    # Pydantic-схемы для Question
|       |-- response.py    # Pydantic-схемы для Response
|-- config.py              # классы конфигурации
|-- run.py                 # точка входа

Структура маршрутов

URLМетодОписание
/questionsGETСписок всех вопросов
/questionsPOSTСоздать новый вопрос
/questions/<id>GETПолучить вопрос по ID
/questions/<id>PUTОбновить вопрос
/questions/<id>DELETEУдалить вопрос
/responsesGETСтатистика ответов
/responsesPOSTДобавить ответ