使用 Flask-RESTful 設(shè)計 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反轉(zhuǎn)url的時候指定的,如果不寫endpoit,那么就會使用視圖的名字的小寫來作為endpoint
2.add_resource的第二個參數(shù)時訪問這個視圖函數(shù)的url,這個url可以跟之前的route一樣,傳遞參數(shù),并且可以傳遞多個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/關(guān)顧也能訪問

flask_restful數(shù)據(jù)驗證

驗證的包,使用reqparse
基本用法:

parse = reqparse.RequestParser()
        parse.add_argument('username', type=str, help='用戶名驗證錯誤')
        parse.add_argument('pwd', type=str, help='密碼驗證錯誤')
        args = parse.parse_args()

add_argument可以指定的參數(shù)

  • default
  • required 是否是必須的
  • type 這個參數(shù)的類型,可以使用自帶的,或者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標準返會參數(shù)(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還是跟模型相對應(yīng)的
        'content': fields.String(default="")
    }
    # restful規(guī)范中,定義好了參數(shù),即使這個參數(shù)沒有值,也應(yīng)該返會一個none
    @marshal_with(resource_fields)
    def get(self):
        # return {'title': 1}
        return article
api.add_resource(ArticleView, '/ariticle/', endpoint='article')

  • 使用 resource_fields 把要定義的字段全部寫好,可以設(shè)置默認值,空字符串等
  • 使用marshal_with進行綁定,那么在方法中,只返會了其中一個字段的話,其余字段就是none,沒設(shè)置默認值的話(return {'title': 1})
    也可以定義類,字段要匹配,然后直接return 類

flask_restful標準返會參數(shù)(2)

  • 重命名
  • 默認值
  • 復(fù)雜結(jié)構(gòu)
    列表就使用 fields.List 字典(對象)就用fields.Nested來設(shè)置


    image.png

flask_restful細節(jié)注意

  • 結(jié)合藍圖使用
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還是跟模型相對應(yīng)的
        'content': fields.String(default="")
    }

    # restful規(guī)范中,定義好了參數(shù),即使這個參數(shù)沒有值,也應(yīng)該返會一個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代碼,或者模板,就應(yīng)該使用api.representation這個裝飾器來定義一個函數(shù),在這個函數(shù)中,應(yīng)該對html代碼進行一個封裝,在返會,代碼如下

@api.representation('text/html')
def out_html(data, code, headers):
    print(data)#data就是一個html結(jié)構(gòu)
    #在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 設(shè)計 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章節(jié)-1", content="入門教程1")
task2 = Task(id=2, title="python章節(jié)-2", content="入門教程2")
task3 = Task(id=3, title="python章節(jié)-3", content="入門教程3")
task_list.append(task1)
task_list.append(task2)
task_list.append(task3)
# 在請求前我們模擬點數(shù)據(jù)
resource_fields = {
    'id': fields.Integer(),
    'title': fields.String(default="未錄入"),
    'content': fields.String(default="無內(nèi)容")
}
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是否,存在,存在就提示返會資源存在,但是接口返會中會返會默認的結(jié)構(gòu)

{
    "id": 0,
    "title": "未錄入",
    "content": "無內(nèi)容"
}

使用自定義錯誤,

Flask-restful 用法及自定義參數(shù)錯誤信息
創(chuàng)建errors文件,

from flask_restful import abort
class ResponseCode:
    code_success = 200  # 凡是成功都用
    CODE_NO_PARAM = 400  # 參數(shù)錯誤
    CODE_NOT_LOGIN = 401  # 未認證
    CODE_NOTFOUND = 404  # 資源不存在
    CODE_SERVER_ERROE = 500  # 服務(wù)器錯誤

    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的[],{},""格式和有數(shù)據(jù)一樣,避免前端報錯
def custom_abord(http_status_code, *args, **kwargs):
    if http_status_code == 400:
        # 重定義400返回參數(shù)
        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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容