从本文起,笔者将会更新一系列Flask学习笔记。
本文将会讲述在Flask中如何创建RESTful API。在此之前,我们有必要了解下什么是RESTful架构。
RESTful架构
RESTful架构自从2000年被Roy Feilding提出后就受到广泛关注,并被成功地应用于成千上万的系统之中。REST已经是web相关应用中的重要技术之一,它极有可能也会在手机和IOT相关应用中快速增长。RESTful架构受欢迎之处,在于它是目前最流行的一种互联网软件架构,其结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
那么,什么是RESTful架构?
REST,即Representational State Transfer的缩写。
资源(Resources)
REST的名称"表现层状态转化"中,省略了主语。“表现层"其实指的是"资源”(Resources)的"表现层"。
所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。你可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。
表现层(Representation)
“资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的"表现层”(Representation)。
比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现。
URI只代表资源的实体,不代表它的形式。它的具体表现形式,应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对"表现层"的描述。
状态转化(State Transfer)
访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。
互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State Transfer)。而这种转化是建立在表现层之上的,所以就是"表现层状态转化"。
客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。
动词 | CRUD | URL | 操作 |
---|---|---|---|
GET | Read | http://host/resource | 获取所有的资源 |
GET | Read | http://host/resource/1 | 获取id为1的资源 |
POST | Create | http://host/resource | 使用POST方法,从表格(form)数据中新建资源 |
PUT | Update | http://host/resource/1 | 对id为1的现有资源进行修改 |
DELETE | Delete | http://host/resource/1 | 删除id为1的资源 |
关于RESTful API的例子
下面我们将用Flask框架来实现RESTful风格的API,用于模拟数据库中persons表中的新增、修改、查询和删除操作。
完整的Python实现代码如下:
# -*- coding: utf-8 -*-
from flask import Flask, request, jsonify
app = Flask(__name__)
persons = [{'name': 'Alex', 'city': 'New York'},
{'name': 'Bob', 'city': 'London'}]
@app.route('/persons', methods=['GET'])
def index():
return jsonify(persons)
@app.route('/persons/<int:_id>', methods=['GET'])
def get_person_by_id(_id):
if _id in range(len(persons)):
return jsonify(persons[_id])
else:
return jsonify(f"{_id} is not in db.")
@app.route('/persons/<int:_id>', methods=['PUT'])
def update_person_by_id(_id):
data = request.json
if data['city']:
persons[_id]["city"] = data['city']
if data['name']:
persons[_id]["name"] = data['name']
return jsonify({"person": data})
@app.route('/persons/<int:_id>', methods=['DELETE'])
def delete_person_by_id(_id):
if _id in range(len(persons)):
person = persons[_id]
persons.remove(person)
return jsonify(person)
else:
return jsonify(f"{_id} is not in db.")
@app.route('/persons', methods=['POST'])
def create_person():
data = request.json
persons.append(data)
return jsonify({"person": data})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True)
已有Python第三方模块flask-restful
可快速完成Restful风格的API开发,实现代码如下:
# -*- coding: utf-8 -*-
from flask import Flask
from flask_restful import reqparse, abort, Api, Resource
app = Flask(__name__)
api = Api(app)
persons = [{'name': 'Tom', 'city': 'New York'},
{'name': 'Green', 'city': 'London'}]
def abort_person_doesnt_exist(_id):
if _id not in range(len(persons)):
abort(404, message=f"id {_id} doesn't exist")
parser = reqparse.RequestParser()
parser.add_argument('name', type=str, default='')
parser.add_argument('city', type=str, default='')
class Person(Resource):
def get(self, _id):
abort_person_doesnt_exist(_id)
return persons[_id]
def delete(self, _id):
abort_person_doesnt_exist(_id)
person = persons[_id]
persons.remove(person)
return person
def put(self, _id):
abort_person_doesnt_exist(_id)
args = parser.parse_args()
if args['city']:
persons[_id]["city"] = args['city']
if args['name']:
persons[_id]["name"] = args['name']
return persons[_id]
class Persons(Resource):
def get(self):
return persons
def post(self):
args = parser.parse_args()
persons.append({'name': args['name'], 'city': args['city']})
return args
api.add_resource(Persons, '/persons')
api.add_resource(Person, '/persons/<int:_id>')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000, debug=True)
利用Postman发送请求
我们使用Postman来发送HTTP请求,用于测试接口是否完成对应的功能。以下是测试过程
- 获取所有的人物(GET请求)
- 获取id为1的人物(GET请求)
- 获取id为2的人物(GET请求,会报错)
- 修改id为1的人物(PUT请求)
- 获取所有的人物(GET请求)
- 新增人物(POST请求)
- 获取所有的人物(GET请求,此时获取id为2的人物不会报错)
- 删除id为1的人物(DELETE请求)
- 获取所有的人物(GET请求)
总结
本文重点介绍了Restful框架,以及如何在Flask中实现Restful风格的API。
Flask是一个简单好用,稳定高效,且久经考验的Web框架,笔者后续将持续地学习Flask框架并输出文章及自己的体会和心得,欢迎大家关注。
参考文献
- 书籍Mastering Flask Web Development(Second Edition), Daniel Gasper and Jack Stouffer, Chapter 8, Page 157-166
- Flask-RESTful: http://www.pythondoc.com/Flask-RESTful/index.html