使用 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

猜你喜欢

转载自blog.csdn.net/frone/article/details/85003907