使用 Flask-RESTful 设计 RESTful API

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容