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 的界面。