Flask + Vue.js : Part 3
- Part 1 : environment, flask HelloWorld, blueprint
- Part 2 : Flask config, logging, unit-testing, SQLAlchemy
- Part 3 : Restful API, Marshmallow, Swagger apidoc
- Part 4 : Flask-Admin, Flask-Security
- Part 5 : Vue.js
Restful API, marshmallow
这个部分制作 json 格式的 API。利用 marshmallow 来定义 API 的 json 格式。
pip install flask_marshmallow
pip install marshmallow-sqlalchemy
file ./dodo/utils/gadget.py 加入这两行:
from flask_marshmallow import Marshmallow
ma = Marshmallow()
file ./dodo/warehouse/ma_schema.py:
from marshmallow import fields
from ..utils.gadget import ma
from ..model.warehouse import Product, Item
class ProductSchema(ma.Schema):
    id = fields.Int()
    name = fields.Str()
class ItemSchema(ma.Schema):
    id = fields.Int()
    name = fields.Str()
    product = fields.Nested(ProductSchema)
    date_produce = fields.Date()
schema_items = ItemSchema(many=True)
file ./dodo/warehouse/api.py:
from flask import Blueprint, jsonify
from flask import current_app as app
from ..model.warehouse import Item
from sqlalchemy.orm import joinedload
from .ma_schema import schema_items
from ..utils.gadget import db
blueprint_api = Blueprint('warehouse_api', __name__)
@blueprint_api.route('/item', methods=['GET'])
def get_items():
    query = db.session.query(Item).filter(Item.date_produce < '2017-08-01')
    items = query.options(joinedload(Item.product)).all()
    data = schema_items.dump(items)[0]
    return jsonify(data)
file ./dodo/app.py
from .warehouse.api import blueprint_api as warehouse_api
def create_app():
    ...
    app.register_blueprint(warehouse_api, url_prefix='/warehouse')
    ...
file ./dodo_test/test_warehouse.py
import json
from pprint import pformat
class WarehouseTestCase(DodoTestCase):
    def test_api_items(self):
        rv = self.client.get(
            '/warehouse/item',
            headers={'content-type': 'application/json'})
        data = json.loads(rv.data)
        self.app.logger.info('return object: \n%s', pformat(data))
        self.assertEqual(len(data), 2, 'Should return 2 objects')
Take a look at our work.
python -m unittest dodo_test.test_warehouse.WarehouseTestCase.test_api_items
# 18-05-21 18:28:29 INFO - application start. __name__ : dodo.app
# 18-05-21 18:28:29 INFO - return object: 
# [{'date_produce': '2017-07-31',
#   'id': 4,
#   'product': {'id': 2, 'name': 'curry lunchbox'}},
#  {'date_produce': '2017-06-01',
#   'id': 5,
#   'product': {'id': 3, 'name': 'instant noodle'}}]
# .
# ----------------------------------------------------------------------
# Ran 1 test in 0.047s
Swagger apidoc
使用 Swagger UI 提供 Open API 格式的说明文件。
pip install flasgger
pip install apispec
为 API method 提供 docstring, Swagger 会将这里的讯息转换成 apidoc 在 UI 上呈现。
file ./dodo/warehouse/api.py
...
@blueprint_api.route('/item', methods=['GET'])
def get_items():
    """
    Item list
    ---
    tags:
      - warehouse
    description: Get all items in the store
    responses:
        200:
            description: list of items
            schema:
                $ref: '#/definitions/Item'
    """
    query = db.session.query(Item).filter(Item.date_produce < '2017-08-01')
...
file ./dodo/utils/swagger.py
from flasgger import APISpec, Swagger
from ..warehouse.api import get_items
from ..warehouse.ma_schema import ProductSchema, ItemSchema
def setup_swagger(app):
    spec = APISpec(
        title='dodo',
        version='0.0.1',
        plugins=[
            'apispec.ext.flask',
            'apispec.ext.marshmallow'
        ]
    )
    template = spec.to_flasgger(
        app,
        definitions=[ProductSchema, ItemSchema],
        paths=[get_items]
    )
    swag = Swagger(app, template=template)
file ./dodo/app.py
from .utils.swagger import setup_swagger
...
def create_app():
    ...
    setup_database(app)
    setup_swagger(app)
    return app
启动 flask 后,访问 http://localhost:5000/apidocs/ 就会看到 apidoc 的界面。
