使用 flask_restful 來開發API

需求

在雙十一買了阿里云云小蜜的培訓課程,花了幾天學了一下,不過考了兩次都沒有考過,但是能夠熟練使用雲小蜜來搭建業務了,爲了整合一些外部數據,例如天氣,交通,電影啥的,需要封裝處理一下第三方API或者調用自己的數據庫。最後的需求就是變成RESTFUL API了,可以把這個請求地址直接放到雲小蜜裏邊。

什麼叫restful

REST的名稱"表現層狀態轉化"中,省略了主語。“表現層"其實指的是"資源”(Resources)的"表現層"。
所謂"資源",就是網絡上的一個實體,或者說是網絡上的一個具體信息。它可以是一段文本、一張圖片、一首歌曲、一種服務,總之就是一個具體的實在。你可以用一個URI(統一資源定位符)指向它,每種資源對應一個特定的URI。要獲取這個資源,訪問它的URI就可以,因此URI就成了每一個資源的地址或獨一無二的識別符。

客戶端用到的手段,只能是HTTP協議。具體來說,就是HTTP協議裏面,四個表示操作方式的動詞:GET、POST、PUT、DELETE。它們分別對應四種基本操作:GET用來獲取資源,POST用來新建資源(也可以用於更新資源),PUT用來更新資源,DELETE用來刪除資源。

  • GET /tickets # 獲取ticket列表
  • GET /tickets/12 # 查看某個具體的ticket
  • POST /tickets # 新建一個ticket
  • PUT /tickets/12 # 更新ticket 12.
  • DELETE /tickets/12 #刪除ticekt 12

代碼

# -*- coding:utf-8 -*-
import os
from flask import Flask, abort
from flask_restful import reqparse, abort, Api, Resource
from flask_restful import fields, marshal
from resources import weather_info

app = Flask(__name__)
api = Api(app)

tasks = [
    {
        'todo_id': 1,
        'title': u'Buy groceries',
        'description': u'Milk, Cheese, Pizza, Fruit, Tylenol',
        'done': False
    },
    {
        'todo_id': 2,
        'title': u'Learn Python',
        'description': u'Need to find a good Python tutorial on the web',
        'done': False
    }
]

task_fields = {
    'title': fields.String,
    'description': fields.String,
    'done': fields.Boolean,
    'uri': fields.Url('task')
}


def abort_if_todo_doesnt_exist(todo_id):
    """
    如果數據庫(內存)中沒有存儲 todo_id 標識的數據 返回404 否則返回該條數據
    :param todo_id: 標識id
    :return: todo_id 標識的數據
    """
    task = filter(lambda t: t['todo_id'] == todo_id, tasks)
    if len(task) == 0:
        abort(404, message="Todo {todo_id} doesn't exist".format(todo_id=todo_id))
    else:
        return task[0]


class Task(Resource):
    def __init__(self):
        # 使用 RequestParser來 解析傳進來的參數
        self.reqparse = reqparse.RequestParser()
        self.reqparse.add_argument('title', type=str, location='json')
        self.reqparse.add_argument('description', type=str, location='json')
        self.reqparse.add_argument('done', type=bool, location='json')
        super(Task, self).__init__()

    def get(self, todo_id):
        task = abort_if_todo_doesnt_exist(todo_id)
        # 使用 marshal 按照 task_fields的定義來包裝task
        return marshal(task, task_fields), 201

    def delete(self, todo_id):
        task = abort_if_todo_doesnt_exist(todo_id)
        tasks.remove(task)
        # del task
        return marshal(tasks, task_fields), 204

    def put(self, todo_id):
        new_task = abort_if_todo_doesnt_exist(todo_id)
        args = self.reqparse.parse_args()
        print(args)
        for k, v in args.iteritems():
            if v is not None:
                new_task[k] = v
        print(new_task)
        return marshal(new_task, task_fields), 201


class TaskList(Resource):
    def __init__(self):
        self.reqparse = reqparse.RequestParser()
        self.reqparse.add_argument('todo_id', type=int, required=True,
                                   help='No todo id provided', location='json')
        self.reqparse.add_argument('title', type=str, required=True,
                                   help='No task title provided', location=['json'])
        self.reqparse.add_argument('description', type=str, default="", location='json')
        self.reqparse.add_argument('done', type=bool, default=False, location='json')
        super(TaskList, self).__init__()

    def get(self):
        return marshal(tasks, task_fields), 201

    def post(self):
        args = self.reqparse.parse_args()
        new_task = {}
        for k, v in args.iteritems():
            if v is not None:
                new_task[k] = v
        tasks.append(new_task)
        return marshal(new_task, task_fields), 202


class Index(Resource):
    def get(self):
        weinfo = weather_info.getWeatherInfo("beijing")
        return {"result": weinfo}, 200


class WeatherInfo(Resource):
    def __init__(self):
        self.reqparse = reqparse.RequestParser()
        self.reqparse.add_argument("city", required=True,
                                   help='No city provided')

    def post(self):
        args = self.reqparse.parse_args()
        print(args)
        weinfo = weather_info.getWeatherInfo(args['city'])
        return {"result": weinfo}, 200

# 添加RESTFUL API的 解析路徑
api.add_resource(TaskList, '/todo/api/v1.0/tasks', endpoint='tasks')
# <int:todo_id> todo_id 要能對應到解析函數的變量名稱
api.add_resource(Task, '/todo/api/v1.0/tasks/<int:todo_id>', endpoint='task')
api.add_resource(Index, '/', endpoint='index')
#
api.add_resource(WeatherInfo, '/weather', endpoint='weather')

if __name__ == '__main__':
    # 運行API接口程序 可以指定端口及 host
    app.run(host='0.0.0.0', port=8889, debug=True)

參考資料

http://www.pythondoc.com/Flask-RESTful/quickstart.html
https://flask-restful.readthedocs.io/en/latest/
http://www.pythondoc.com/flask-restful/third.html
https://jiayi.space/post/ji-yu-flaskde-restful-apihou-duan-bi-ji
https://www.cnblogs.com/binlin1987/p/6971808.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章