Рубрики
Без рубрики

Как создать RESTful API с помощью Python и Flask

Как создать Restful API с помощью python Flask

Автор оригинала: Mide Olarewaju.

В течение некоторого времени я работал с Python, но недавно мне довелось попробовать Flask, поэтому я почувствовал, что было бы неплохо написать об этом. В этой статье я расскажу о Flask и о том, как вы можете использовать его для создания Restful API.

Flask-это микрорамка на основе Python, которая позволяет быстро создавать веб-приложения; “микро” в микрорамке просто означает, что Flask стремится сохранить ядро простым, но расширяемым .

Что такое ОТДЫХ?

REST – это аббревиатура RE presentational S tate T ransfer. Это архитектурный стиль и подход к коммуникациям, который часто используется при разработке веб – сервисов.

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

В этом руководстве вы познакомитесь с созданием API Restful с помощью Flask в сочетании с другими расширениями – Flask-RESTful, flask_migrate, marshmallow и т. Д. В конце вы создадите простой API для комментариев. API будет иметь конечные точки, которые можно использовать для добавления категории , просмотра категорий , обновления категории , удаления категории , добавления комментариев и просмотра комментариев .

Flask не выходит из коробки со всеми расширениями, необходимыми для создания полного API fledge. Однако есть много расширений, которые можно подключить к Flask, чтобы вы могли создавать потрясающие API.

В конце этого руководства у вас должны быть доступны конечные точки этого API:

  • GET/api/Category – Получение всех категорий

  • POST/api/Категория – Добавить новую категорию

  • PUT/api/Category – Обновление категории

  • УДАЛИТЬ/api/Категория – Удалить категорию

  • GET/api/Comment – Получение всех сохраненных комментариев

  • СООБЩЕНИЕ/api/Комментарий – Добавить новый комментарий

Прежде Чем Вы Начнете

  • Убедитесь, что в вашей системе установлен Python3.x .

  • Для этого урока мы будем использовать PostgreSQL database. Установите базу данных Postgres, если она еще не установлена.

  • Убедитесь, что virtualenv установлен в вашей системе.

Шаг 0: Настройка приложения

  • Во-первых, создайте структуру приложения в любом месте вашей системы:
project/
├── app.py
├── migrate.py
├── Model.py
├── requirements.txt
├── resources
│   └── Hello.py
└── run.py

Если вы предпочитаете командную строку для создания папок и файлов, вы можете использовать следующую команду:

# Create folders
$ mkdir project && cd project && mkdir resources

# Create files
$ touch app.py migrate.py Model.py requirements.txt run.py config.py && cd resources && touch Hello.py && cd ../
  • Затем откройте терминал и компакт-диск (изменить каталог) в корневую папку приложения – project .

  • Затем создайте и активируйте виртуальную среду .

virtualenv-это инструмент для создания изолированных сред Python. virtualenv создает папку, содержащую все необходимые исполняемые файлы для использования пакетов, необходимых проекту Python.

Создает виртуальную среду

$ python3.6 -m venv env

ОПЕРАЦИОННАЯ:

$ python -m venv env

Используемая команда зависит от того, какая из них связана с вашей установкой python3.

Активирует виртуальную среду

$ source env/bin/activate

Добавьте следующие расширения в requirements.txt :

flask==0.12.2
flask_restful==0.3.6
flask_script==2.0.6
flask_migrate==2.1.1
marshmallow==2.14.0
flask_sqlalchemy==2.3.2
flask_marshmallow==0.8.0
marshmallow-sqlalchemy==0.13.2
psycopg2==2.7.5

Приведенный выше файл содержит все расширения python, которые будет использовать наш API.

  • колба – Это микрорамка для Python

  • flask_restful – Это расширение для Flask, которое добавляет поддержку для быстрого создания API REST.

  • flask_script – Это расширение, которое обеспечивает поддержку написания внешних сценариев в Flask.

  • flask_migrate – Это расширение, которое обрабатывает миграции баз данных SQLAlchemy для приложений Flask с использованием перегонного куба.

  • marshmallow – Это библиотека ORM/ODM/framework-agnostic для преобразования сложных типов данных, таких как объекты, в собственные типы данных Python и из них. Мы будем использовать это для проверки. Это используется для сериализации и десериализации объектов.

  • flask_sqlalchemy – Это расширение для Flask, которое добавляет поддержку SQLAlchemy.

  • flask_marshmallow – Это уровень интеграции для Flask и marshmallow (библиотека сериализации/десериализации объектов), который добавляет дополнительные функции в marshmallow.

  • marshmallow-sqlalchemy – Это добавляет дополнительные функции в marshmallow.

  • psycopg – Это адаптер PostgreSQL для языка программирования Python.

Шаг 1: Установите все зависимости:

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

$ pip install -r requirements.txt

Это позволит загрузить и установить все расширения в requirements.txt .

Шаг 2: Настройка конфигурации

Добавьте следующий код в config.py :

import os

# You need to replace the next values with the appropriate values for your configuration

basedir = os.path.abspath(os.path.dirname(__file__))
SQLALCHEMY_ECHO = False
SQLALCHEMY_TRACK_MODIFICATIONS = True
SQLALCHEMY_DATABASE_URI = "postgresql://username:password@localhost/database_name"

Здесь мы определили некоторую конфигурацию, которую будет использовать API. Мы также используем базу данных PostgreSQL. Если вы предпочитаете другие базы данных, вам просто нужно соответствующим образом изменить значение.

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

SQLALCHEMY_DATABASE_URI = "sqlite:///app.db"

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

Шаг 3: Создайте точки входа в API

Добавьте следующий код в app.py :

from flask import Blueprint
from flask_restful import Api
from resources.Hello import Hello

api_bp = Blueprint('api', __name__)
api = Api(api_bp)

# Route
api.add_resource(Hello, '/Hello')

Здесь мы импортировали Blueprint из flask, а также Api из flask_restful. Импортированный Api добавит в flask некоторую функциональность, которая поможет нам добавить маршруты и упростить некоторые процессы.

api_bp('api', __name__) – создает схему, которая позже будет зарегистрирована в приложении.

api.add_resource(Hello, '/Hello') – создает маршрут – /Hello . add_resource принимает два параметра – Hello и Hello/|, где Hello - это класс, который мы импортировали, и Hello |/- это маршрут, который мы определили для этого ресурса.

Теперь давайте создадим класс Hello , о котором мы упоминали выше. Добавьте следующий код в – resources/Hello.py :

from flask_restful import Resource


class Hello(Resource):
    def get(self):
        return {"message": "Hello, World!"}

В классе Hello мы определили функцию – get . Это означает, что любой запрос GET на конечной точке /Hello будет попадать в эту функцию.

Поэтому, если вам нужен метод POST, у вас будет что-то вроде:

    def post(self):
        return {"message": "Hello, World!"}

Наконец, добавьте следующий код в run.py :

from flask import Flask

def create_app(config_filename):
    app = Flask(__name__)
    app.config.from_object(config_filename)
    
    from app import api_bp
    app.register_blueprint(api_bp, url_prefix='/api')

    from Model import db
    db.init_app(app)

    return app


if __name__ == "__main__":
    app = create_app("config")
    app.run(debug=True)

Шаг 4: Запуск сервера

С вашего терминала убедитесь, что вы находитесь в корневой папке приложения, а затем выполните эту команду:

$ python run.py

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

 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 136-695-873

Теперь посетите URL-адрес(http://127.0.0.1:5000/api/Hello), вы должны увидеть вывод, как показано ниже:

{
    "hello": "world"
}

Потрясающе!

Шаг 5: Создание моделей.

Следующий шаг – написать наши модели. Flask предоставляет разработчикам мощь и гибкость ORM SQLAlchemy для управления данными приложения и запроса к ним. ORM расшифровывается как Object Relational Mapper, это инструмент, который позволяет разработчикам хранить и извлекать данные с использованием объектно-ориентированных подходов и решает проблему несоответствия импеданса объектно-реляционных данных.

Кроме того, Flask-SQLAlchemy-это расширение, которое обеспечивает поддержку ORM SQLAlchemy в рамках Flask.

В … Model.py файл, добавьте в него следующий код:

from flask import Flask
from marshmallow import Schema, fields, pre_load, validate
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy


ma = Marshmallow()
db = SQLAlchemy()


class Comment(db.Model):
    __tablename__ = 'comments'
    id = db.Column(db.Integer, primary_key=True)
    comment = db.Column(db.String(250), nullable=False)
    creation_date = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), nullable=False)
    category_id = db.Column(db.Integer, db.ForeignKey('categories.id', ondelete='CASCADE'), nullable=False)
    category = db.relationship('Category', backref=db.backref('comments', lazy='dynamic' ))

    def __init__(self, comment, category_id):
        self.comment = comment
        self.category_id = category_id


class Category(db.Model):
    __tablename__ = 'categories'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(150), unique=True, nullable=False)

    def __init__(self, name):
        self.name = name


class CategorySchema(ma.Schema):
    id = fields.Integer()
    name = fields.String(required=True)


class CommentSchema(ma.Schema):
    id = fields.Integer(dump_only=True)
    category_id = fields.Integer(required=True)
    comment = fields.String(required=True, validate=validate.Length(1))
    creation_date = fields.DateTime()

Здесь у нас есть две модели – Комментарий и Категория класс. Этот класс определяет структуру таблицы. __имя таблицы__ используется для объявления имени таблицы, связанного с этой моделью.

Мы также определили столбцы для нашей таблицы, используя, например:

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(150), unique=True, nullable=False)

id и name являются столбцами таблицы, а значение после = определяет структуру столбцов. Вы можете прочитать больше о создании схемы таблицы здесь

Далее для проверки используются схемы Category и Comment Schema . Здесь мы определили некоторые правила (например: required=True ). Вы можете прочитать больше здесь

Шаг 6: Запуск миграций

В migrate.py файл добавьте в него следующий код:

from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from Model import db
from run import create_app

app = create_app('config')

migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)


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

В приведенном выше коде мы создали команду для запуска миграции из командной строки.

Миграции

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

  • Запустите инициализацию миграции, используя команду db init следующим образом:
  $ python migrate.py db init
  Creating directory /home/user/Desktop/pylinone/migrations ... done
  Creating directory /home/user/Desktop/pylinone/migrations/versions ... done
  Generating /home/user/Desktop/pylinone/migrations/alembic.ini ... done
  Generating /home/user/Desktop/pylinone/migrations/README ... done
  Generating /home/user/Desktop/pylinone/migrations/env.py ... done
  Generating /home/user/Desktop/pylinone/migrations/script.py.mako ... done
  Please edit configuration/connection/logging settings in '/home/user/Desktop/pylinone/migrations/alembic.ini' before
  proceeding.

Сценарий также создал новую подпапку миграции в папке с подпапкой версий и многими другими файлами.

Запустите второй сценарий, который заполнит сценарий миграции обнаруженными изменениями в моделях. В этом случае мы впервые заполняем сценарий миграции, и, следовательно, сценарий миграции создаст таблицы, в которых будут сохранены наши две модели: Категория и комментарий:

Запустите миграцию:

$ python migrate.py db migrate
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added table 'category'
INFO  [alembic.autogenerate.compare] Detected added table 'comment'
  Generating /home/user/Desktop/pylinone/migrations/versions/015c8b601c6b_.py ... done
  • Затем примените миграцию к базе данных. Выполните команду обновления:

  • Выполните команду обновления:

python migrate.py db upgrade
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 015c8b601c6b, empty message

При каждом изменении моделей баз данных повторяйте команды migrate и upgrade .

Шаг 7: Добавление ресурсов категории

Создайте новый файл resources/Category.py . Это позаботится обо всей логике, связанной с категориями. Добавьте приведенный ниже код в resources/Category.py :

from flask import request
from flask_restful import Resource
from Model import db, Category, CategorySchema

categories_schema = CategorySchema(many=True)
category_schema = CategorySchema()

class CategoryResource(Resource):
    def get(self):
        categories = Category.query.all()
        categories = categories_schema.dump(categories).data
        return {'status': 'success', 'data': categories}, 200

Здесь мы создали метод get для извлечения категорий. Теперь у нас есть новая конечная точка – http://127.0.0.1:5000/api/Category .

Использование Категории.query.all() , мы извлекли все категории в базе данных и использовали categories_schema.dump(категории).data , мы десериализовали полученные данные.

Далее, давайте добавим метод POST для создания новой категории. Добавьте следующий код в resources/Category.py :

...
    def post(self):
        json_data = request.get_json(force=True)
        if not json_data:
               return {'message': 'No input data provided'}, 400
        # Validate and deserialize input
        data, errors = category_schema.load(json_data)
        if errors:
            return errors, 422
        category = Category.query.filter_by(name=data['name']).first()
        if category:
            return {'message': 'Category already exists'}, 400
        category = Category(
            name=json_data['name']
            )

        db.session.add(category)
        db.session.commit()

        result = category_schema.dump(category).data

        return { "status": 'success', 'data': result }, 201

Далее, давайте добавим метод PUT для обновления категории. Обновление resources/Category.py как показано ниже:

...
    def put(self):
        json_data = request.get_json(force=True)
        if not json_data:
               return {'message': 'No input data provided'}, 400
        # Validate and deserialize input
        data, errors = category_schema.load(json_data)
        if errors:
            return errors, 422
        category = Category.query.filter_by(id=data['id']).first()
        if not category:
            return {'message': 'Category does not exist'}, 400
        category.name = data['name']
        db.session.commit()

        result = category_schema.dump(category).data

        return { "status": 'success', 'data': result }, 204

Наконец, давайте добавим метод УДАЛЕНИЯ для удаления категории. Добавьте следующий код в resources/Category.py :

...
    def delete(self):
        json_data = request.get_json(force=True)
        if not json_data:
               return {'message': 'No input data provided'}, 400
        # Validate and deserialize input
        data, errors = category_schema.load(json_data)
        if errors:
            return errors, 422
        category = Category.query.filter_by(id=data['id']).delete()
        db.session.commit()

        result = category_schema.dump(category).data

        return { "status": 'success', 'data': result}, 204

Наконец, импортируйте эти ресурсы в app.py . Обновление app.py точно так, как показано ниже:

from flask import Blueprint
from flask_restful import Api
from resources.Hello import Hello
from resources.Category import CategoryResource


api_bp = Blueprint('api', __name__)
api = Api(api_bp)

# Routes

api.add_resource(Hello, '/Hello')
api.add_resource(CategoryResource, '/Category')

В категории ресурсы мы создали 4 конечные точки:

ПОЛУЧИТЬ … http://127.0.0.1:5000/api/Category

ПОСТ – http://127.0.0.1:5000/api/Category

ПОЛОЖИТЬ – http://127.0.0.1:5000/api/Category

УДАЛИТЬ – http://127.0.0.1:5000/api/Category

Шаг 8: Добавление ресурсов комментариев

Создайте новый файл resources/Comment.py . Это позаботится обо всех комментариях, связанных с логикой.

from flask import jsonify, request
from flask_restful import Resource
from Model import db, Comment, Category, CommentSchema

comments_schema = CommentSchema(many=True)
comment_schema = CommentSchema()

class CommentResource(Resource):
    def get(self):
        comments = Comment.query.all()
        comments = comments_schema.dump(comments).data
        return {"status":"success", "data":comments}, 200

    def post(self):
        json_data = request.get_json(force=True)
        if not json_data:
               return {'message': 'No input data provided'}, 400
        # Validate and deserialize input
        data, errors = comment_schema.load(json_data)
        if errors:
            return {"status": "error", "data": errors}, 422
        category_id = Category.query.filter_by(id=data['category_id']).first()
        if not category_id:
            return {'status': 'error', 'message': 'comment category not found'}, 4

# Routes

api.add_resource(Hello, '/Hello')
api.add_resource(CategoryResource, '/Category')
api.add_resource(CommentResource, '/Comment')

Шаг 9: Конечные точки тестирования

Теперь у нас есть следующие доступные конечные точки:

  • ПОСТ – http://127.0.0.1:5000/api/category – для добавления категорий.