利用Python和Flask快速开发RESTful API

REST,即Representational State Transfer,翻译过来叫做“表现层状态转化”。关于REST以及RESTful API的相关概念、理解等,建议参考:理解RESTful架构 - 阮一峰的网络日志。这里我们不讨论这些理论知识,而是以Flask为基础,讲解如何快速开发RESTful API。

在利用Flask开发RESTful API之前,我们需要了解标准的HTTP方法有哪些?

GET获取全部的资源http://example.com/api/ordersGET获取某个特定资源http://example.com/api/orders/123POST 创建新资源 http://example.com/api/ordersPUT更新特定资源 http://example.com/api/orders/123DELETE删除特定资源 http://example.com/api/orders/123

对应到RESTful API,得到标准的API接口:

GET 检索资源列表 http://[hostname]/todo/api/v1.0/items GET 检索某个特定资源http://[hostname]/todo/api/v1.0/items/[item_id]POST 创建新资源http://[hostname]/todo/api/v1.0/itemsPUT 更新资源http://[hostname]/todo/api/v1.0/items/[item_id]DELETE 删除资源http://[hostname]/todo/api/v1.0/items/[item_id]

针对上边的几种API接口的返回结果,返回状态码等,有一些规则说明:

GET检索资源列表,返回一个资源数组或字典,并返回状态码200,表示请求成功。GET检索某个特定资源,返回单个资源,并返回状态码200,表示请求成功。POST创建新资源,返回创建后的资源,并返回状态码201,表示资源创建成功。PUT更新资源,返回更新后的资源,并返回状态码201,表示资源更新成功。DELETE删除资源,返回空,并返回状态码204,表示资源删除成功,服务器已无该资源。

Flask是Python中常用的一种web开发框架,关于其基本知识大家可以自行学习。这里我们利用Flask中的Flask-RESTful库,快速生成RESTful API。

首先安装Flask-RESTful库:

pip install flask-restful

我们利用官方文档Flask-RESTful documentation中的实例,讲解该扩展库的用法。由于官方实例中的一些变量名不好理解,这里稍微做一些修改。

(1)引入需要的库名、函数、变量等,并做简单的Application初始化:

from flask import Flask from flask_restful import reqparse, abort, Api, Resource app = Flask(__name__) api = Api(app)

(2)定义我们需要操作的资源类型(都是json格式的):

ITEMS = { item1: {name: Allen, age: 19}, item2: {name: Lily, age: 18}, item3: {name: James, age: 20}, }

(3)Flask-RESTful提供了一个用于参数解析的RequestParser类,类似于Python中自带的argparse类,可以很方便的解析请求中的-d参数,并进行类型转换。

parser = reqparse.RequestParser() parser.add_argument(name, type=str, required=True, help=need name data) parser.add_argument(age, type=int, required=True, help=need age data)

(4)我们观察标准的API接口,这里的接口可以分为两类:带有item_id的,和不带有item_id的。前者是操作单一资源,后者是操作资源列表或新建一个资源。

从操作单一资源开始,继承Resource类,并添加put / get / delete方法:

# 操作(put / get / delete)单一资源 class Todo(Resource): def put(self, item_id): args = parser.parse_args() item = {name: args[name], age: args[age]} ITEMS[item_id] = item return item, 201 def get(self, item_id): abort_if_item_doesnt_exist(item_id) return ITEMS[item_id], 200 def delete(self, item_id): abort_if_item_doesnt_exist(item_id) del ITEMS[item_id] return , 204

(5)继续操作资源列表,继承Resource类,并添加get / post方法:

# 操作(post / get)资源列表 class TodoList(Resource): def get(self): return ITEMS, 200 def post(self): args = parser.parse_args() item_id = get_new_item_id() ITEMS[item_id] = {name: args[name], age: args[age]} return ITEMS[item_id], 201

(6)资源操作类定义完毕之后,需要设置路由,即告诉Python程序URL的对应关系。

# 设置路由 api.add_resource(TodoList, /items) api.add_resource(Todo, /items/<item_id>)

这样当我们请求url时,就能根据url类型,找到相应的资源类,并调用对应方法。

(7)使用实例:

得到资源列表:

~$ curl :5000/items -X GET { "item1": { "age": 19, "name": "Allen" }, "item2": { "age": 18, "name": "Lily" }, "item3": { "age": 20, "name": "James" } }

得到特定资源:

~$ curl :5000/items/item1 -X GET { "age": 19, "name": "Allen" }

更新特定资源,并返回更新后的资源:

~$ curl :5000/items/item1 -X PUT -d "name=Allen&age=20" { "age": 20, "name": "Allen" }

创建新资源,并返回创建后的资源:

~$ curl :5000/items -X POST -d "name=Brown&age=20" { "age": 20, "name": "Brown" }

删除资源:

~$ curl :5000/items/item4 -X DELETE

看到这里,基本的RESTful API就算是完成了,包含了数据库中数据的“增删查改”各个操作。也许很多人看完之后会觉得很简单,或者说根本就不值得自己去学习。但其实REST的基本思想虽然容易理解(这也是设计这种思想的目的),但想真正用好也不容易。本文中我们只是考虑了最最基本的用法,除此之外还有很多高级的用法和逻辑,比如:

如何返回指定个数的资源,即limit操作。如何指定资源返回时跳过的资源个数,即offset操作。结合上边两条,如何实现分页,以及限定每页中资源的个数?如何对返回的资源进行排序?如何指定过滤条件?如何实现批量操作?比如批量更新、批量删除等。如何实现“请求验证”,即输入特定的用户名密码才会返回数据,否则认为非法请求。如何处理各种异常?

可以想象,一个真正规范的RESTful API并不容易写,需要考虑的逻辑非常多,具体如何使用还需要大家在平时的工作中,根据自己的业务需求,自行设计。

最后老规矩,文中代码整理后Push到Github:xianhu/LearnPython

=============================================================

作者主页:笑虎(Python爱好者,关注爬虫、数据分析、数据挖掘、数据可视化等)

作者专栏主页:撸代码,学知识 - 知乎专栏

作者GitHub主页:撸代码,学知识 - GitHub

欢迎大家拍砖、提意见。相互交流,共同进步!

==============================================================