1. 安装 Flask-RESTful
Flask-RESTful
(venv) D:\python-code\flask-vuejs-madblog\back-end> pip install flask-restful
(venv) D:\python-code\flask-vuejs-madblog\back-end> pip freeze > requirements.txt
2. 初始化插件
back-end/app/api_v2back-end/app/api_v2/__init__.pyback-end/app/api_v2/app.py
from flask import Blueprint
from flask_restful import Api


# Blueprint
bp = Blueprint('api_v2', __name__)
# Init Flask-RESTful
api = Api(bp)
蓝图(Blubprint)flask_restful.Api()bp
back-end/app/__init__.py
...
from app.api_v2.app import bp as api_v2_bp

...
def configure_blueprints(app):
    # 注册 blueprint
    app.register_blueprint(api_bp, url_prefix='/api')
    app.register_blueprint(api_v2_bp, url_prefix='/api/v2')
...
Flask-RESTful/api/v2http://127.0.0.1:5000/api/v2/ping
3. 创建第一个资源
Flask-RESTful资源(Resources)Flask MethodViewflask_restful.Resource
class Resource(MethodView):
    """
    Represents an abstract RESTful resource. Concrete resources should
    extend from this class and expose methods for each supported HTTP
    method. If a resource is invoked with an unsupported HTTP method,
    the API will return a response with status 405 Method Not Allowed.
    Otherwise the appropriate method is called and passed all arguments
    from the url rule used when adding the resource to an Api instance. See
    :meth:`~flask_restful.Api.add_resource` for details.
    """
    representations = None
    method_decorators = []

    def dispatch_request(self, *args, **kwargs):

        # Taken from flask
        #noinspection PyUnresolvedReferences
        meth = getattr(self, request.method.lower(), None)
        if meth is None and request.method == 'HEAD':
            meth = getattr(self, 'get', None)
        assert meth is not None, 'Unimplemented method %r' % request.method

        if isinstance(self.method_decorators, Mapping):
            decorators = self.method_decorators.get(request.method.lower(), [])
        else:
            decorators = self.method_decorators

        for decorator in decorators:
            meth = decorator(meth)

        resp = meth(*args, **kwargs)

        if isinstance(resp, ResponseBase):  # There may be a better way to test
            return resp

        representations = self.representations or OrderedDict()

        #noinspection PyUnresolvedReferences
        mediatype = request.accept_mimetypes.best_match(representations, default=None)
        if mediatype in representations:
            data, code, headers = unpack(resp)
            resp = representations[mediatype](data, code, headers)
            resp.headers['Content-Type'] = mediatype
            return resp

        return resp
资源back-end/app/api_v2/resources/back-end/app/api_v2/resources/ping.py
from flask_restful import Resource


class Ping(Resource):
    def get(self):
        return {'message': 'Pong!'}
back-end/app/api_v2/resources/back-end/app/api_v2/resources/__init__.py
back-end/app/api_v2/urls.py
from app.api_v2.app import api
from app.api_v2.resources.ping import Ping


# 统一注册路由
api.add_resource(Ping, '/', '/ping')

Endpoints:

add_resource()endpointflask.url_for()
1. 单个 URL
api.add_resource(Foo, '/foo')

2. 多个 URL
api.add_resource(Foo, '/foo1', '/foo2')

3. 同时指定 endpoint,默认是资源名的小写,比如 Foo 资源的 endpoint=foo
api.add_resource(Foo, '/foo1', '/foo2', endpoint='foo_ep')
back-end/app/api_v2/app.pyurls.py
from flask import Blueprint
from flask_restful import Api


# Blueprint
bp = Blueprint('api_v2', __name__)
# Init Flask-RESTful
api = Api(bp)

# 统一注册路由
from app.api_v2 import urls

最终的目录结构如下:

flask-restful 目录结构

此时,启动 Flask 应用:

(venv) D:\python-code\flask-vuejs-madblog\back-end> flask run
 * Serving Flask app "madblog.py" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 968-712-707
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Postmanhttp://127.0.0.1:5000/api/v2http://127.0.0.1:5000/api/v2/pingPong!

flask-restful-02.png

flask-restful-03.png

POST405

flask-restful-04.png

4. 重新设计 User API
GET/api/v2/usersPOST/api/v2/usersGET/api/v2/users/PUT/api/v2/users/DELETE/api/v2/users/
URLhttp://127.0.0.1:5000/api/v2/usershttp://127.0.0.1:5000/api/v2/users/Flask-RESTfulResourceback-end/app/api_v2/resources/users.py
from flask_restful import Resource


# User: shows a single user item and lets you delete a user item
class UserAPI(Resource):
    def get(self, id):
        pass

    def delete(self, id):
        pass

    def put(self, id):
        pass


# UserList: shows a list of all users, and lets you POST to add new user
class UserListAPI(Resource):
    def get(self):
        pass

    def post(self):
        pass
back-end/app/api_v2/urls.py
...
from app.api_v2.resources.users import User, UserList

...
api.add_resource(UserListAPI, '/users', endpoint='users')
api.add_resource(UserAPI, '/users/<int:id>', endpoint='user')

现在只需要考虑各 HTTP 操作方法的具体实现即可

4.1 注册新用户

from flask import url_for
from flask_restful import Resource, reqparse, inputs
from app.extensions import db
from app.models import User


# UserList: shows a list of all users, and lets you POST to add new user
class UserListAPI(Resource):
    def __init__(self):
        self.parser = reqparse.RequestParser(bundle_errors=True)
        self.parser.add_argument('username', type=str, required=True, help='Please provide a valid username.', location='json')
        self.parser.add_argument('email', type=inputs.regex('^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'), required=True, help='Please provide a valid email address.', location='json')
        self.parser.add_argument('password', type=str, required=True, help='Please provide a valid password.', location='json')
        super(UserListAPI,