解析以及验证请求

当我在以前的文章中实现此服务器的时候,我自己对请求的数据进行验证。例如,在之前版本中如何处理 PUT 的:

1. @app.route('/todo/api/v1.0/tasks/<int:task_id>', methods = ['PUT'])
   @auth.login_required
   def update_task(task_id):
       task = filter(lambda t: t['id'] == task_id, tasks)
       if len(task) == 0:
           abort(404)
       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']) is not unicode:
           abort(400)
       if 'done' in request.json and type(request.json['done']) is not bool:
           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': make_public_task(task[0]) } )

在这里, 我必须确保请求中给出的数据在使用之前是有效,这样使得函数变得又臭又长。

Flask-RESTful 提供了一个更好的方式来处理数据验证,它叫做 RequestParser 类。这个类工作方式类似命令行解析工具 argparse。

首先,对于每一个资源需要定义参数以及怎样验证它们:

1. from flask.ext.restful import reqparse

3. class TaskListAPI(Resource):
4. def __init__(self):
5. self.reqparse = reqparse.RequestParser()
6. self.reqparse.add_argument('title', type = str, required = True,
7. help = 'No task title provided', location = 'json')
8. self.reqparse.add_argument('description', type = str, default = "", location = 'json')
9. super(TaskListAPI, self).__init__()

11. # ...

13. class TaskAPI(Resource):
14. def __init__(self):
15. self.reqparse = reqparse.RequestParser()
16. self.reqparse.add_argument('title', type = str, location = 'json')
17. self.reqparse.add_argument('description', type = str, location = 'json')
18. self.reqparse.add_argument('done', type = bool, location = 'json')
19. super(TaskAPI, self).__init__()

21. # ...

在 TaskListAPI 资源中,POST 方法是唯一接收参数的。参数“标题”是必须的,因此我定义一个缺少“标题”的错误信息。当客户端缺少这个参数的时候,Flask-RESTful 将会把这个错误信息作为响应发送给客户端。“描述”字段是可选的,当缺少这个字段的时候,默认的空字符串将会被使用。一个有趣的方面就是 RequestParser 类默认情况下在 request.values 中查找参数,因此 location 可选参数必须被设置以表明请求过来的参数是 request.json 格式的。

TaskAPI 资源的参数处理是同样的方式,但是有少许不同。PUT 方法需要解析参数,并且这个方法的所有参数都是可选的。

当请求解析器被初始化,解析和验证一个请求是很容易的。 例如,请注意 TaskAPI.put() 方法变的多么地简单:

1. def put(self, id):
2. task = filter(lambda t: t['id'] == id, tasks)
3. if len(task) == 0:
4. abort(404)
5. task = task[0]
6. args = self.reqparse.parse_args()
7. for k, v in args.iteritems():
8. if v != None:
9. task[k] = v
10. return jsonify( { 'task': make_public_task(task) } )

使用 Flask-RESTful 来处理验证的另一个好处就是没有必要单独地处理类似 HTTP 400 错误,Flask-RESTful 会来处理这些。