美文网首页flaskFlaskpython相关库
使用 Flask-RESTful 设计 RESTful API

使用 Flask-RESTful 设计 RESTful API

作者: 蒲小帅丶 | 来源:发表于2018-12-11 16:27 被阅读0次
    flask-restful插件
    #基本使用
    from flask_restful import Resource, Api
    app = Flask(__name__)
    api = Api(app=app)
    # restful
    class LoginView(Resource):
        def get(self):
            return {'username': "蒲小帅"}
    api.add_resource(LoginView, '/login/', endpoint='login')
    
    

    注意,endpoint是用来给url_for反转url的时候指定的,如果不写endpoit,那么就会使用视图的名字的小写来作为endpoint
    2.add_resource的第二个参数时访问这个视图函数的url,这个url可以跟之前的route一样,传递参数,并且可以传递多个url.

    # restful
    class LoginView(Resource):
        def get(self, name="蒲小帅"):
            return {'username': name}
    
    api.add_resource(LoginView, '/login/<name>/', '/login1/', endpoint='login')
    

    浏览器输入http://127.0.0.1:1112/login1/也能访问,输入http://127.0.0.1:1112/login/关顾也能访问

    flask_restful数据验证

    验证的包,使用reqparse
    基本用法:

    parse = reqparse.RequestParser()
            parse.add_argument('username', type=str, help='用户名验证错误')
            parse.add_argument('pwd', type=str, help='密码验证错误')
            args = parse.parse_args()
    

    add_argument可以指定的参数

    • default
    • required 是否是必须的
    • type 这个参数的类型,可以使用自带的,或者flask_restful的inputs中的类型。常用url,regex,date
      1.url,验证是不是url
      2.regex
    • choices 选项
    • help 错误信息
      trim 是否提取出前后的空格
    class LoginView(Resource):
        def post(self):
            parse = reqparse.RequestParser()
            parse.add_argument('username',trim=True, type=str,default='张三', help='用户名验证错误')
            parse.add_argument('age', type=int, help='年龄上传不对')
            parse.add_argument('gender', type=str,choices=['1','2'],help='没有可选项')
            parse.add_argument('pwd', type=str, help='密码验证错误',required=True)
            parse.add_argument('center', type=inputs.url, help='个人中心连接失败')
            parse.add_argument('phone',type=inputs.regex(r'1[3578]\d{9}'),help='手机号码错误')
            parse.add_argument('time', type=inputs.date, help='生日验证错误')
            args = parse.parse_args()
            print(args)
            return  args.get('username')
    
    
    api.add_resource(LoginView, '/login/', endpoint='login')
    
    image.png
    image.png

    flask_restful标准返会参数(1)

    from flask_restful import Resource, Api, reqparse, inputs, fields, marshal_with
    class Article(object):
        def __init__(self, title, content):
            self.title = title
            self.content = content
    article = Article(title="I am title",content="I am content")
    class ArticleView(Resource):
        resource_fields = {
            'title1': fields.String(default="标题",attribute="title"),#这样在json显示是title1,别名title还是跟模型相对应的
            'content': fields.String(default="")
        }
        # restful规范中,定义好了参数,即使这个参数没有值,也应该返会一个none
        @marshal_with(resource_fields)
        def get(self):
            # return {'title': 1}
            return article
    api.add_resource(ArticleView, '/ariticle/', endpoint='article')
    
    
    • 使用 resource_fields 把要定义的字段全部写好,可以设置默认值,空字符串等
    • 使用marshal_with进行绑定,那么在方法中,只返会了其中一个字段的话,其余字段就是none,没设置默认值的话(return {'title': 1})
      也可以定义类,字段要匹配,然后直接return 类

    flask_restful标准返会参数(2)

    • 重命名
    • 默认值
    • 复杂结构
      列表就使用 fields.List 字典(对象)就用fields.Nested来设置


      image.png

    flask_restful细节注意

    • 结合蓝图使用
    from  flask import Blueprint
    article_bp=Blueprint('article',__name__,url_prefix='/article')
    from flask_restful import Resource, Api, reqparse, inputs, fields, marshal_with
    api=Api(article_bp)
    class Article(object):
        def __init__(self, title, content):
            self.title = title
            self.content = content
    article = Article(title="I am title",content="I am content")
    class ArticleView(Resource):
        resource_fields = {
            'title1': fields.String(default="标题",attribute="title"),#这样在json显示是title1,别名title还是跟模型相对应的
            'content': fields.String(default="")
        }
    
        # restful规范中,定义好了参数,即使这个参数没有值,也应该返会一个none
        @marshal_with(resource_fields)
        def get(self):
            # return {'title': 1}
            return article
    api.add_resource(ArticleView, '/article/', endpoint='article')
    

    1.在蓝图中使用flask-restful,就可以不在使用app了,直接使用蓝图生成的app

    • 使用flask-restful渲染模板

    2.如果在flask-restful视图中想要返会html代码,或者模板,就应该使用api.representation这个装饰器来定义一个函数,在这个函数中,应该对html代码进行一个封装,在返会,代码如下

    @api.representation('text/html')
    def out_html(data, code, headers):
        print(data)#data就是一个html结构
        #在representation,必须返会一个response对象
        resp=make_response(data)
        return  resp
    ......
    class ListView(Resource):
        def get(self):
            return render_template('index1.html')
    api.add_resource(ListView, '/list/', endpoint='list')
    

    使用flask_restful案例

    我们把使用 Python 和 Flask 设计 RESTful API中的案例用flask_restful插件来写一下。

    from flask import Flask, jsonify, abort, make_response, request, redirect, url_for
    from flask_httpauth import HTTPBasicAuth
    from flask_restful import Resource, Api, reqparse, fields, marshal_with
    import json
    
    app = Flask(__name__)
    
    api = Api(app)
    
    
    class Task(object):
        def __init__(self, id, title, content):
            self.title = title
            self.id = id
            self.content = content
        def __repr__(self):
            return self.title
    
    
    task_list = []
    task1 = Task(id=1, title="python章节-1", content="入门教程1")
    task2 = Task(id=2, title="python章节-2", content="入门教程2")
    task3 = Task(id=3, title="python章节-3", content="入门教程3")
    task_list.append(task1)
    task_list.append(task2)
    task_list.append(task3)
    # 在请求前我们模拟点数据
    resource_fields = {
        'id': fields.Integer(),
        'title': fields.String(default="未录入"),
        'content': fields.String(default="无内容")
    }
    class TaskListAPI(Resource):
        @marshal_with(resource_fields)
        def get(self):
            return task_list
        def post(self):
            pass
    class TaskAPI(Resource):
        @marshal_with(resource_fields)
        def get(self, task_id):
            print("id是" + str(task_id))
            # 对象,这里不能写[id]了,直接.id
            task = list(filter(lambda t: t.id == task_id, task_list))
            print(task)
            if len(task) == 0:
                abort(404)
            else:
                return task[0]
        @marshal_with(resource_fields)
        def delete(self, task_id):
            # 对象,这里不能写[id]了,直接.id
            task = list(filter(lambda t: t.id == task_id, task_list))
            print(task)
            if len(task) == 0:
                abort(404)
            else:
                data = task[0]
                task_list.remove(data)
                return task_list
    class DEL_TASK(Resource):
        @marshal_with(resource_fields)
        def post(self):
            if not request.form or not 'id' in request.form:
                abort(404)
            id = request.form["id"]
            print(id)
            task = list(filter(lambda t: t.id == int(id), task_list))
            if len(task) == 0:
                abort(404)
            else:
                data = task[0]
                task_list.remove(data)
                return task_list
    class Add_TASK(Resource):
        @marshal_with(resource_fields)
        def post(self):
            if not request.form or not 'id' in request.form:
                abort(404)
            id = request.form.get("id")
            title = request.form.get("title")
            content = request.form.get("content")
            task = list(filter(lambda t: t.id == int(id), task_list))
            if len(task) ==0:
                task_data = Task(id=id, title=title, content=content)
                task_list.append(task_data)
                return task_list
            else:
                return jsonify({"msg":'资源已存在'}),403
    @app.errorhandler(404)
    def not_found(error):
        return jsonify({'error': 'not found'}), 404
    
    api.add_resource(Add_TASK, '/todo/api/v1.0/tasks/add', endpoint='task_add')
    api.add_resource(DEL_TASK, '/todo/api/v1.0/tasks/del', endpoint='task_del')
    api.add_resource(TaskAPI, '/todo/api/v1.0/tasks/<int:task_id>', endpoint='task')
    api.add_resource(TaskListAPI, '/todo/api/v1.0/tasks', endpoint='tasks')
    
    if __name__ == '__main__':
        app.run(port=1211, debug=True)
    
    

    问题,在增加的过程中,虽然我们验证id是否,存在,存在就提示返会资源存在,但是接口返会中会返会默认的结构

    {
        "id": 0,
        "title": "未录入",
        "content": "无内容"
    }
    

    使用自定义错误,

    Flask-restful 用法及自定义参数错误信息
    创建errors文件,

    from flask_restful import abort
    class ResponseCode:
        code_success = 200  # 凡是成功都用
        CODE_NO_PARAM = 400  # 参数错误
        CODE_NOT_LOGIN = 401  # 未认证
        CODE_NOTFOUND = 404  # 资源不存在
        CODE_SERVER_ERROE = 500  # 服务器错误
    
        msg = {
            code_success: "success",
            CODE_NO_PARAM: "params error",
            CODE_NOT_LOGIN: "not auth",
            CODE_NOTFOUND: "source not found",
            CODE_SERVER_ERROE: "sorry,server is error"
        }
    
    def generate_response(data=None,message=ResponseCode.msg[ResponseCode.code_success], code=ResponseCode.code_success):
        return {
            'message': message,
            'code': code,
            'data': data
        }
    
    #增加一个type,方便控制 data的[],{},""格式和有数据一样,避免前端报错
    def custom_abord(http_status_code, *args, **kwargs):
        if http_status_code == 400:
            # 重定义400返回参数
            abort(400, **generate_response(message=ResponseCode.msg[http_status_code],code=http_status_code))
        abort(http_status_code)
    
    

    app.py文件中

    import flask_restful
    from  errors import custom_abord,generate_response,ResponseCode
    flask_restful.abort = custom_abord
    .....
    

    使用

    class TaskAPI(Resource):
        def get(self):
            # 对象,这里不能写[id]了,直接.id
            parse = reqparse.RequestParser()
            parse.add_argument("id", type=int, help="be  int",required=True)
            id = parse.parse_args().get("id")
            task = list(filter(lambda t: t["id"] == id, task_list))
            if len(task) == 0:
                custom_abord(ResponseCode.CODE_NO_PARAM)
            else:
                return generate_response(data=task[0],code=ResponseCode.code_success)
    ....
    api.add_resource(TaskAPI, '/todo/api/v1.0/task/', endpoint='task')
    

    效果图


    image.png image.png

    相关文章

      网友评论

        本文标题:使用 Flask-RESTful 设计 RESTful API

        本文链接:https://www.haomeiwen.com/subject/abushqtx.html