解析以及验证请求

当我在以前的文章中实现此服务器的时候,我自己对请求的数据进行验证。例如,在之前版本中如何处理 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
  2.  
  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__()
  10.  
  11. # ...
  12.  
  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__()
  20.  
  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 会来处理这些。