Фреймворк flask.

Установим flask.

pip install flask

Создадим минимальное приложение run.py.

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

Для того, чтобы запускать приложение, необходимо иметь переменную FLASK_APP в окружении коммандного интерпретатора bash.

Ее можно добавить в адресной строке.

export FLASK_APP=start.py

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

Но мы создадим файл .env c переменными, которые должны входить в окружение.

FLASK_APP=run.py

Теперь нам необходима библиотека, которая способна его прочитать и добавить эти переменные в окружение (конфигурацию приложения) на этапе выполнения программы.

Одна из таких библиотек называется dotenv.

pip install python-dotenv

Теперь создадим функцию создания приложения с заданной конфигурацией.

from flask import Flask
from dotenv import load_dotenv, dotenv_values

def create_app():
    flask_app = Flask(__name__)
    load_dotenv()
    flask_app.config.update(dotenv_values())
    return flask_app

app = create_app()

@app.route('/')
def hello_world():
    return 'Hello, World!'

Добавим еще пару переменных в .env.

FLASK_APP=run.py
DEBUG = True
FLASK_ENV=development

DEBUG - режим отладки

FLASK_ENV - режим при котором приложение будет перегружаться при изменениях скриптов.

Например так:

 * Detected change in '/home/zdimon/Desktop/flask-api/run.py', reloading
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 319-920-800

Альтернативным способом можно настроить окружение не через .env файл, а через классы в файле, например в configmodule.py:

class Config(object):
    DEBUG = False
    TESTING = False
    DATABASE_URI = 'sqlite:///:memory:'

class ProductionConfig(Config):
    DATABASE_URI = 'mysql://user@localhost/foo'

class DevelopmentConfig(Config):
    DEBUG = True

class TestingConfig(Config):
    TESTING = True

И потом ‘втолкнуть’ в приложение так:

app.config.from_object('configmodule.ProductionConfig')

Перенос роутов в отдельный файл.

Мы можем перенести роуты в отдельные файлы и не хранить все в run.py

Облечгим до предела run.py

from app import app
import apps

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

Вынесем настройки приложения в отдельный модуль app.py

from flask import Flask
from dotenv import load_dotenv, dotenv_values

def create_app():
    flask_app = Flask(__name__)
    load_dotenv()
    flask_app.config.update(dotenv_values())
    return flask_app

app = create_app()

В новой папке apps/route создадим модуль index.py

from app import app

@app.route('/')
def index():
    return 'Hello, World!'

И для того, чтобы сработал импорт import apps в run.py добавим следующее в apps/init.py

from .route.index import index

Тут мы будем импортировать каждый новый модуль роутов.

База данных

Установим библиотеки

pip install Flask-SQLAlchemy psycopg2-binary

Создадим объект базы данных в app.py

...

from flask_sqlalchemy import SQLAlchemy

def create_db(c_app):
    return SQLAlchemy(c_app)


...

app = create_app() 
db = create_db(app)

Для подключения к БД необходимо задать специальные переменные в окружении.

ссылка на документацию

Задаем переменную SQLALCHEMY_DATABASE_URI с правами и прочим для коннекта.

SQLALCHEMY_DATABASE_URI=postgresql://postgres:1q2w3e@localhost:5432/flask-api

Создадим класс модели данных в новой папке models и в файле users.py

from app import db

class Users(db.Model):
    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String())
    password = db.Column(db.String())

    def __repr__(self):
        return '<id {}-{}>'.format(self.id, self.username)

Теперь для того, чтобы добавить эту таблицу необходимо создать и запустить миграцию.

Для этого установим инструмент flask-migrate

pip install flask-migrate

Создадим объект миграций в app.py

from flask_migrate import Migrate
...
app = create_app() 
db = create_db(app)
migrate = Migrate(app, db)

Создадим базу данных fask-api в любом клиенте postgres например в pgAdmin3

Теперь у нас стала доступной команда

flask db

Следующим шагом будет создание репозитория (директории) для миграций.

flask db init

И далее создание первой миграции.

flask db migrate

При этом получаем

No changes in schema detected.

Импортируем модели после создания объекта миграций в app.py

...
migrate = Migrate(app, db)
from apps.models.users import Users

Теперь можно последовательно запускать команды

flask db migrate

Которая создаст миграцию.

И второй командой ее запустить.

flask db upgrade

Установка swagger

Эта библиотка создаст удобный интерфейс для тестирования.

pip install flasgger

Создаем обьект Swagger из приложения.

from flasgger import Swagger
swagger = Swagger(app)

Добавляем описание в функцию роутинга.

from app import app

@app.route('/')
def index():
    """Example endpoint returning a list of colors by palette
    This is using docstrings for specifications.
    ---
    parameters:
      - name: palette
        in: path
        type: string
        enum: ['all', 'rgb', 'cmyk']
        required: true
        default: all
    definitions:
      Palette:
        type: object
        properties:
          palette_name:
            type: array
            items:
              $ref: '#/definitions/Color'
      Color:
        type: string
    responses:
      200:
        description: A list of colors (may be filtered by palette)
        schema:
          $ref: '#/definitions/Palette'
        examples:
          rgb: ['red', 'green', 'blue']
    """
    return 'Hello, World!'

Использование схем Marshmallow.

Эти схемы позволяют преобразовывать python объекты схем модели в json.

Устанавливаем библиотеку.

pip install marshmallow apispec

Создадим новый модуль schemas/user.py

from flasgger import Schema, fields

class User(Schema):
    name = fields.Str()
    username = fields.Str()
    password = fields.Str()

Создадим контроллер (представление) в новом модуле routes/users.py

from flasgger import Swagger, SwaggerView
from ..shemas.user import User
from app import app

class UsersView(SwaggerView):
    parameters = [
        {
            "name": "name",
            "type": "string",
            "required": True,
        },
        {
            "name": "username",
            "type": "string",
            "required": True,
        },
        {
            "name": "password",
            "type": "string",
            "required": True,
        }
    ]
    responses = {
        200: {
            "description": "Create user",
            "schema": User
        }
    }

    def post(self):
        """

        Creating a new user.

        """

        return jsonify({'message': 'Ok'})

app.add_url_rule(
    '/user/create',
    view_func=UsersView.as_view('create user'),
    methods=['POST']
)

Подключим этот роут в apps/init.py

from .routes.users import UsersView

Добавим файл к параметрам.

class UsersView(SwaggerView):
    parameters = [
        ...
        {
            "name": "file",
            "type": "file",
            "required": False,
        }
     ....