早在一个笔记应用引出的全栈工程师的能力锻炼这篇文章中我就提到过应该尽量去编写API来实现一个web应用,在此之前也使用PHP实现了一个小的demo(具体参见用php实现一个app的API)。事实证明,越来越多的设备进入互联网(物联网时代的到来),我们需要更加优秀和耐用的API。于是,时隔半年,这一次我来展现给大家如何使用python的微框架flask,快速的实现一个Restful风格的API。
为什么是Restful?
必须有一种统一的机制,方便不同的前端设备与后端进行通信。这导致API构架的流行,RESTful API是目前比较成熟的一套互联网应用程序的API设计理论。
工作原理
额,工作原理就是,客户端发送request,服务端response一个json对象。
Restful Url的要求和在flask中的实现
在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的"集合"(collection),所以API中的名词也应该使用复数。
举个例子:比如我们有一个数据资源,是一种对编程语言的描述,大概如下:
datas = [{'name': 'javascript', 'useto': 'web development'},
{'name': 'python', 'useto': 'do anything'},
{'name': 'php', 'useto': 'web development'},
{'name': 'c++', 'useto': 'web server'}]
上面定义了一个数组,数组内包含了一些字典,每一个数组元素其实就是对某一种编程语言的简单描述。
当我们要获取数据集合的时候就可以这么请求:
https://myservice.com/api/v1/languages
当我们要获取一条数据的详细信息的时候,可以这么请求:
https://myservice.com/api/v1/languages/python
请求的方法 (解释了为什么RestfulAPI的url里面没有动词)
我觉得你应该受够了类似于下列的请求url了:
http://test.com/getstudents.do
http://test.com/getinfobyid.action
http://test.com/updateinfobyid.action
说实话,这样的url我也很讨厌。所以我用REST呀!
RestFul对于资源的具体操作类型,由HTTP动词表示。
常用的HTTP动词有下面五个。
GET(SELECT):从服务器取出资源(一项或多项)。
POST(CREATE):在服务器新建一个资源。
PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
DELETE(DELETE):从服务器删除资源。
恩,相同的url,执行不同的动作,得到的结果是不同的,习惯了之后,你就会爱上这种设计。
如何实现 直接贴上代码
首先,关于flask的知识,pocoo的文档真心不错,用上半个小时过一遍快速如么就基本能看懂下面的代码了。
其次,下面的代码对数据源(一个数组)进行了CRUD的操作,返回json对象。
json对象被封装成两种情况:
第一种带数据和状态信息的响应:
例如:
{
"data": [
{
"name": "javascript",
"useto": "web development"
},
{
"name": "python",
"useto": "do anything"
},
{
"name": "php",
"useto": "web development"
},
{
"name": "c++",
"useto": "web server"
}
],
"status": {
"code": 200,
"message": "OK all right."
}
}
当需要获取资源的时候,我们返回一个data对应一个数组,同时返回状态信息
第二种仅仅包含状态信息的响应:
{
"status": {
"code": 404,
"message": "No result matched."
}
}
当仅仅执行增加、删除和修改操作的时候,用户关心的只是操作时否成功,仅需要返回对应的Restful约定的状态信息即可!
在下面代码中,对函数的返回进行了简单的封装
下面代码中的
fullResponse
和statusResponse
来源于自定义的模块restfultools
fullResponse
接受两个参数,一个是自己定义的状态字典,一个是数据集和(数组)
statusResponse
仅仅接收一个自定义的状态字典
Flask主程序, rest.py
from flask import Flask, request, jsonify
from restfultools import * #这个是我自己写的一个简单的数据封装工具(装B的描述)
app = Flask(__name__)
#这是数据源
datas = [{'name': 'javascript', 'useto': 'web development'},
{'name': 'python', 'useto': 'do anything'},
{'name': 'php', 'useto': 'web development'},
{'name': 'c++', 'useto': 'web server'}]
#获取所有的资源 注意我用了复数形式的url
@app.route('/languages')
def getAll():
return fullResponse(R200_OK, datas)
#根据name获取资源中的某一个
@app.route('/language/<string:name>')
def getOne(name):
result = [data for data in datas if data['name'] == name]
if len(result) == 0:
return statusResponse(R404_NOTFOUND)
return fullResponse(R200_OK, result[0])
#POST请求,增加一项
@app.route('/language', methods=['POST'])
def addOne():
request_data = request.get_json()
if not 'name' in request_data or not 'useto' in request_data:
return statusResponse(R400_BADREQUEST)
name = request_data['name']
useto = request_data['useto']
datas.append({'name': name, 'useto': useto})
return statusResponse(R201_CREATED)
#PUT,PATCH 更新资源
#按照RestFul设计:
#PUT动作要求客户端提供改变后的完整资源
#PATCH动作要求客户端可以只提供需要被改变的属性
#在这里统一使用PATCH的方法
@app.route('/language/<string:name>', methods=['PUT', 'PATCH'])
def editOne(name):
result = [data for data in datas if data['name'] == name]
if len(result) == 0:
return statusResponse(R404_NOTFOUND)
request_data = request.get_json()
if 'name' in request_data:
result[0]['name'] = request_data['name']
if 'useto' in request_data:
result[0]['useto'] = request_data['useto']
return statusResponse(R201_CREATED)
#DELETE删除,没什么好说的
@app.route('/language/<string:name>', methods=['DELETE'])
def delOne(name):
result = [data for data in datas if data['name'] == name]
if len(result) == 0:
return statusResponse(R404_NOTFOUND)
datas.remove(result[0])
return statusResponse(R204_NOCONTENT)
自定义的工具模块 restfultools.py
#-*- coding: UTF-8 -*-
from flask import jsonify
# define statu_dics here
R200_OK = {'code': 200, 'message': 'OK all right.'}
R201_CREATED = {'code': 201, 'message': 'All created.'}
R204_NOCONTENT = {'code': 204, 'message': 'All deleted.'}
R400_BADREQUEST = {'code': 400, 'message': 'Bad request.'}
R403_FORBIDDEN = {'code': 403, 'message': 'You can not do this.'}
R404_NOTFOUND = {'code': 404, 'message': 'No result matched.'}
def fullResponse(statu_dic, data):
return jsonify({'status': statu_dic, 'data': data})
def statusResponse(statu_dic):
return jsonify({'status': statu_dic})
关于flask的版本: 0.11
运行的方法和之前有一点点不同:
export FLASK_APP = rest.py
flask run
悄悄的告诉你 以前的方法也支持,不过不推荐!
最后:API开发工具推荐:
PostMan : 一个google-chrome的插件
Json Formatter: 一个Json格式化工具 也是Google-Chrome插件
网友评论