使用 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)系作者
  • 序言:七十年代末玫锋,一起剝皮案震驚了整個濱河市蛾茉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌撩鹿,老刑警劉巖谦炬,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡键思,警方通過查閱死者的電腦和手機础爬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吼鳞,“玉大人看蚜,你說我怎么就攤上這事∨庾溃” “怎么了供炎?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長疾党。 經(jīng)常有香客問我音诫,道長,這世上最難降的妖魔是什么雪位? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任竭钝,我火速辦了婚禮,結(jié)果婚禮上雹洗,老公的妹妹穿的比我還像新娘蜓氨。我一直安慰自己,他們只是感情好队伟,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布穴吹。 她就那樣靜靜地躺著,像睡著了一般嗜侮。 火紅的嫁衣襯著肌膚如雪港令。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天锈颗,我揣著相機與錄音顷霹,去河邊找鬼。 笑死击吱,一個胖子當著我的面吹牛淋淀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播覆醇,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼朵纷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了永脓?” 一聲冷哼從身側(cè)響起袍辞,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎常摧,沒想到半個月后搅吁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體威创,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年谎懦,在試婚紗的時候發(fā)現(xiàn)自己被綠了肚豺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡界拦,死狀恐怖详炬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情寞奸,我是刑警寧澤呛谜,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站枪萄,受9級特大地震影響隐岛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瓷翻,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一聚凹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧齐帚,春花似錦妒牙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至剪菱,卻和暖如春摩瞎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背孝常。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工旗们, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人构灸。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓上渴,卻偏偏與公主長得像,于是被迫代替她去往敵國和親喜颁。 傳聞我的和親對象是個殘疾皇子稠氮,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容