Home » Как создать REST API с Flask на Ubuntu
Как создать REST API с Flask на Ubuntu

Как создать REST API с Flask на Ubuntu

Если разрабатываешь веб-сервисы или просто хочешь быстро поднять API для своего проекта, то Flask — это как раз то, что нужно. Эта статья покажет, как создать REST API с Flask на Ubuntu-сервере. Мы пройдём весь путь от установки зависимостей до деплоя готового решения. Никаких лишних абстракций — только конкретные команды, рабочие примеры и практические советы из реального опыта.

Как это работает: архитектура Flask API

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

Основные компоненты Flask API:

  • Flask-приложение — центральный объект, который обрабатывает HTTP-запросы
  • Роуты — декораторы, которые связывают URL с функциями
  • Blueprint — для организации больших приложений
  • Middleware — для обработки запросов и ответов
  • Сериализаторы — для работы с JSON

Пошаговая настройка окружения

Для начала нужен Ubuntu-сервер. Если у тебя его нет, можешь заказать VPS или использовать выделенный сервер для более серьёзных проектов.

Установка Python и зависимостей

# Обновляем систему
sudo apt update && sudo apt upgrade -y

# Устанавливаем Python и pip
sudo apt install python3 python3-pip python3-venv -y

# Устанавливаем дополнительные пакеты
sudo apt install build-essential libssl-dev libffi-dev python3-dev -y

# Проверяем версию Python
python3 --version

Создание виртуального окружения

# Создаём проект
mkdir flask-api && cd flask-api

# Создаём виртуальное окружение
python3 -m venv venv

# Активируем окружение
source venv/bin/activate

# Устанавливаем Flask и дополнительные пакеты
pip install flask flask-restful flask-cors gunicorn python-dotenv

Создание базового API

Создаём файл app.py с простым REST API:

from flask import Flask, jsonify, request
from flask_restful import Api, Resource
from flask_cors import CORS
import os
from dotenv import load_dotenv

# Загружаем переменные окружения
load_dotenv()

app = Flask(__name__)
api = Api(app)
CORS(app)  # Разрешаем CORS для всех доменов

# Простая база данных в памяти
users = [
    {"id": 1, "name": "Alice", "email": "alice@example.com"},
    {"id": 2, "name": "Bob", "email": "bob@example.com"}
]

class UserList(Resource):
    def get(self):
        return {"users": users}, 200
    
    def post(self):
        data = request.get_json()
        if not data or 'name' not in data or 'email' not in data:
            return {"error": "Missing required fields"}, 400
        
        new_user = {
            "id": len(users) + 1,
            "name": data['name'],
            "email": data['email']
        }
        users.append(new_user)
        return new_user, 201

class User(Resource):
    def get(self, user_id):
        user = next((u for u in users if u['id'] == user_id), None)
        if user:
            return user, 200
        return {"error": "User not found"}, 404
    
    def put(self, user_id):
        user = next((u for u in users if u['id'] == user_id), None)
        if not user:
            return {"error": "User not found"}, 404
        
        data = request.get_json()
        user.update(data)
        return user, 200
    
    def delete(self, user_id):
        global users
        users = [u for u in users if u['id'] != user_id]
        return {"message": "User deleted"}, 200

# Регистрируем роуты
api.add_resource(UserList, '/api/users')
api.add_resource(User, '/api/users/')

@app.route('/health')
def health_check():
    return jsonify({"status": "healthy"}), 200

if __name__ == '__main__':
    port = int(os.getenv('PORT', 5000))
    debug = os.getenv('DEBUG', 'False').lower() == 'true'
    app.run(host='0.0.0.0', port=port, debug=debug)

Создание файла конфигурации

Создаём файл .env для переменных окружения:

PORT=5000
DEBUG=True
SECRET_KEY=your-secret-key-here
DATABASE_URL=sqlite:///app.db

Тестирование API

Запускаем приложение:

# Активируем виртуальное окружение
source venv/bin/activate

# Запускаем Flask
python app.py

Тестируем API с помощью curl:

# Получаем список пользователей
curl -X GET http://localhost:5000/api/users

# Создаём нового пользователя
curl -X POST http://localhost:5000/api/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Charlie", "email": "charlie@example.com"}'

# Получаем конкретного пользователя
curl -X GET http://localhost:5000/api/users/1

# Обновляем пользователя
curl -X PUT http://localhost:5000/api/users/1 \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice Smith"}'

# Удаляем пользователя
curl -X DELETE http://localhost:5000/api/users/1

Добавление базы данных

Для серьёзных проектов понадобится настоящая база данных. Установим SQLite и SQLAlchemy:

pip install flask-sqlalchemy flask-migrate

Создаём файл models.py:

from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

db = SQLAlchemy()

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    
    def to_dict(self):
        return {
            'id': self.id,
            'name': self.name,
            'email': self.email,
            'created_at': self.created_at.isoformat()
        }

Обновляем app.py для работы с базой данных:

from flask import Flask, jsonify, request
from flask_restful import Api, Resource
from flask_cors import CORS
from flask_migrate import Migrate
from models import db, User
import os

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL', 'sqlite:///app.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db.init_app(app)
migrate = Migrate(app, db)
api = Api(app)
CORS(app)

class UserListResource(Resource):
    def get(self):
        users = User.query.all()
        return {"users": [user.to_dict() for user in users]}, 200
    
    def post(self):
        data = request.get_json()
        if not data or 'name' not in data or 'email' not in data:
            return {"error": "Missing required fields"}, 400
        
        # Проверяем, не существует ли пользователь с таким email
        existing_user = User.query.filter_by(email=data['email']).first()
        if existing_user:
            return {"error": "User with this email already exists"}, 400
        
        user = User(name=data['name'], email=data['email'])
        db.session.add(user)
        db.session.commit()
        
        return user.to_dict(), 201

api.add_resource(UserListResource, '/api/users')

# Создаём таблицы при первом запуске
with app.app_context():
    db.create_all()

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)

Настройка production-окружения

Gunicorn как WSGI-сервер

Создаём файл gunicorn_config.py:

import multiprocessing

bind = "0.0.0.0:5000"
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "sync"
worker_connections = 1000
max_requests = 1000
max_requests_jitter = 50
preload_app = True
timeout = 120
keepalive = 2

Запускаем с Gunicorn:

gunicorn -c gunicorn_config.py app:app

Настройка Nginx как reverse proxy

# Устанавливаем Nginx
sudo apt install nginx -y

# Создаём конфигурацию
sudo nano /etc/nginx/sites-available/flask-api

Содержимое конфигурации Nginx:

server {
    listen 80;
    server_name your-domain.com;
    
    location / {
        proxy_pass http://127.0.0.1:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_connect_timeout 30s;
        proxy_send_timeout 30s;
        proxy_read_timeout 30s;
    }
    
    location /health {
        access_log off;
        proxy_pass http://127.0.0.1:5000/health;
    }
}

Активируем конфигурацию:

# Создаём символическую ссылку
sudo ln -s /etc/nginx/sites-available/flask-api /etc/nginx/sites-enabled/

# Тестируем конфигурацию
sudo nginx -t

# Перезапускаем Nginx
sudo systemctl restart nginx

Создание systemd-сервиса

Создаём файл /etc/systemd/system/flask-api.service:

[Unit]
Description=Flask API Service
After=network.target

[Service]
Type=exec
User=www-data
Group=www-data
WorkingDirectory=/path/to/your/flask-api
Environment=PATH=/path/to/your/flask-api/venv/bin
ExecStart=/path/to/your/flask-api/venv/bin/gunicorn -c gunicorn_config.py app:app
ExecReload=/bin/kill -s HUP $MAINPID
Restart=always

[Install]
WantedBy=multi-user.target

Активируем сервис:

sudo systemctl daemon-reload
sudo systemctl enable flask-api
sudo systemctl start flask-api
sudo systemctl status flask-api

Сравнение с другими решениями

Фреймворк Скорость разработки Производительность Сложность Экосистема
Flask Высокая Средняя Низкая Богатая
Django REST Средняя Средняя Высокая Очень богатая
FastAPI Высокая Очень высокая Средняя Растущая
Express.js Высокая Высокая Низкая Огромная

Интересные факты и нестандартные применения

  • Микросервисная архитектура: Flask отлично подходит для создания небольших, специализированных сервисов
  • Обработка WebSocket: с Flask-SocketIO можно создавать real-time приложения
  • Интеграция с Celery: для асинхронной обработки задач
  • GraphQL support: через библиотеку Graphene можно создавать GraphQL API
  • Автоматическая документация: Flask-RESTX генерирует Swagger документацию

Пример интеграции с Celery для фоновых задач

from celery import Celery
import os

def make_celery(app):
    celery = Celery(
        app.import_name,
        backend=app.config['CELERY_RESULT_BACKEND'],
        broker=app.config['CELERY_BROKER_URL']
    )
    celery.conf.update(app.config)
    return celery

app.config.update(
    CELERY_BROKER_URL='redis://localhost:6379/0',
    CELERY_RESULT_BACKEND='redis://localhost:6379/0'
)

celery = make_celery(app)

@celery.task
def send_email(email, message):
    # Логика отправки email
    time.sleep(10)  # Имитация долгой операции
    return f"Email sent to {email}"

@api.route('/send-email', methods=['POST'])
def send_email_endpoint():
    data = request.get_json()
    task = send_email.delay(data['email'], data['message'])
    return jsonify({"task_id": task.id}), 202

Мониторинг и логирование

Добавляем логирование в приложение:

import logging
from logging.handlers import RotatingFileHandler

if not app.debug:
    file_handler = RotatingFileHandler('logs/app.log', maxBytes=10240, backupCount=10)
    file_handler.setFormatter(logging.Formatter(
        '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
    ))
    file_handler.setLevel(logging.INFO)
    app.logger.addHandler(file_handler)
    app.logger.setLevel(logging.INFO)
    app.logger.info('Flask API startup')

Автоматизация развёртывания

Создаём простой скрипт для развёртывания deploy.sh:

#!/bin/bash

# Останавливаем сервис
sudo systemctl stop flask-api

# Обновляем код
git pull origin main

# Активируем виртуальное окружение
source venv/bin/activate

# Устанавливаем зависимости
pip install -r requirements.txt

# Выполняем миграции
flask db upgrade

# Запускаем сервис
sudo systemctl start flask-api

# Проверяем статус
sudo systemctl status flask-api

Заключение и рекомендации

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

Когда использовать Flask:

  • Быстрое прототипирование API
  • Микросервисная архитектура
  • Когда нужен полный контроль над компонентами
  • Небольшие и средние проекты

Когда лучше выбрать альтернативы:

  • Большие корпоративные проекты → Django REST Framework
  • Высокие требования к производительности → FastAPI
  • Нужны готовые решения из коробки → Django

Для production-окружения обязательно используй Gunicorn + Nginx, настрой логирование и мониторинг. Если планируешь высокую нагрузку, рассмотри возможность использования Redis для кеширования и Celery для фоновых задач.

Полезные ссылки:


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

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

Leave a reply

Your email address will not be published. Required fields are marked