六条设计规范定义了一个 REST 系统的特点:
- 客户端-服务器: 客户端和服务器之间隔离,服务器提供服务,客户端进行消费。
- 无状态: 从客户端到服务器的每个请求都必须包含理解请求所必需的信息。换句话说, 服务器不会存储客户端上一次请求的信息用来给下一次使用。
- 可缓存: 服务器必须明示客户端请求能否缓存。
- 分层系统: 客户端和服务器之间的通信应该以一种标准的方式,就是中间层代替服务器做出响应的时候,客户端不需要做任何变动。
- 统一的接口: 服务器和客户端的通信方法必须是统一的。
- 按需编码: 服务器可以提供可执行代码或脚本,为客户端在它们的环境中执行。这个约束是唯一一个是可选的。
HTTP 标准的方法有如下:
========== ===================== ==================================
HTTP 方法 行为 示例
========== ===================== ==================================
GET 获取资源的信息 http://example.com/api/orders
GET 获取某个特定资源的信息 http://example.com/api/orders/123
POST 创建新资源 http://example.com/api/orders
PUT 更新资源 http://example.com/api/orders/123
DELETE 删除资源 http://example.com/api/orders/123
========== ====================== ==================================
应用tasks列表模拟数据库
在客户端用curl模拟浏览器访问资源
GET 获取资源信息
$curl -i http://localhost:5000//todo/api/v1.0/tasks
GET 获取某个特定信息
$curl -i http://localhost:5000//todo/api/v1.0/tasks/id
POST 创建资源
$curl -i -H "Content-type:application/json" -X POST -d '{"title":"hello world","description":""}' http://localhost:5000//todo/api/v1.0/tasks
PUT 跟新资源
$curl -i -H "Content-type:application/json" -X PUT -d '{"title":"hello world","description":""}' http://localhost:5000//todo/api/v1.0/tasks/id
DELETE 删除资源
$curl -i -H "Content-type:application/json" -X DELETE http://localhost:5000//todo/api/v1.0/tasks/id
from flask import Flask, jsonify
from flask import abort
from flask import make_response
from flask import request
app = Flask(__name__)
tasks = [
{
'id': 1,
'title': u'Buy groceries',
'description': u'Milk, Cheese, Pizza, Fruit, Tylenol',
'done': False
},
{
'id': 2,
'title': u'Learn Python',
'description': u'Need to find a good Python tutorial on the web',
'done': False
}
]
@app.route('/todo/api/v1.0/tasks', methods=(['GET']))
def get_tasks():
return jsonify({'tasks':tasks})
@app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=(['GET']))
def get_task(task_id):
task = filter(lambda t: t['id'] == task_id, tasks)
if len(task) == 0:
abort(404)
return jsonify({'tasks':tasks[0]})
@app.errorhandler(404)
def not_found(error):
return make_response(jsonify({'error': 'Not found'}), 404)
@app.route('/todo/api/v1.0/tasks', methods=['POST'])
def create_task():
if not request.json or not 'title' in request.json:
abort(400)
task = {
'id':tasks[-1]['id']+1,
'title':request.json['title'],
'description':request.json.get('description',''),
'done':False
}
tasks.append(task)
return jsonify({'task':task}),201
@app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['PUT'])
def update_task(task_id):
task = filter(lambda t: t['id']==task_id, tasks)
if len(task) == 0:
abort(400)
if not request.json:
abort(400)
if 'title' in request.json and type(request.json['title']) != unicode:
abort(400)
if 'description' in request.json and type(request.json['description']) != unicode:
abort(400)
if 'done' in request.json and type(request.json['done']) != unicode:
abort(400)
task[0]['title'] = request.json.get('title',task[0]['title'])
task[0]['description'] = request.json.get('description', task[0]['description'])
task[0]['done'] = request.json.get('done',task[0]['done'])
return jsonify({'task':task[0]})
@app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['DELETE'])
def delete_task(task_id):
task = filter(lambda t:t['id'] == task_id, tasks)
if len(task) == 0:
abort(400)
tasks.remove(task[0])
return jsonify({'result':True})
if __name__ == '__main__':
app.run(debug=True)