Flask 学习-33.Flask-RESTful 请求参数校验reqparse.RequestParser()
前言
接口请求参数的校验是个大的工作量,参数比较少的时候还可以一个个去判断,参数多了写起来就很麻烦了。
reqparse 解析请求参数
尽管 Flask 能够简单地访问请求数据(比如查询字符串或者 POST 表单编码的数据),验证表单数据仍然很痛苦。Flask-RESTful 内置了支持验证请求数据,它使用了一个类似 argparse 的库。
from flask.ext.restful import reqparse
parser = reqparse.RequestParser()
parser.add_argument('rate', type=int, help='Rate to charge for this resource')
args = parser.parse_args()
需要注意地是与 argparse 模块不同,reqparse.RequestParser.parse_args() 返回一个 Python 字典而不是一个自定义的数据结构。
使用 reqparse 模块同样可以自由地提供聪明的错误信息。如果参数没有通过验证,Flask-RESTful 将会以一个 400 错误请求以及高亮的错误信息回应。
$ curl -d 'rate=foo' http://127.0.0.1:5000/
{'status': 400, 'message': 'foo cannot be converted to int'}
使用 strict=True 调用 parse_args 能够确保当请求包含你的解析器中未定义的参数的时候会抛出一个异常。
args = parser.parse_args(strict=True)
json 参数校验示例
restful-full 开发的接口,一般传json格式,以注册功能为例
在没有加 reqparse之前,通过request.get_json() 获取传过来的json数据
# 获取入参
data = request.get_json()
print(f'请求入参:{args}')
使用 reqparse 获取传过来的数据,并对数据校验,视图部分代码
class Register(Resource):
def post(self):
# 校验入参
parser = reqparse.RequestParser()
parser.add_argument('username', required=True, type=str, help='username is required')
parser.add_argument('password', required=True, type=str, help='password is required')
args = parser.parse_args()
print(f'请求入参:{args}')
return jsonify({
"code": 0,
"msg": "success"
})
# 注册
api.add_resource(Register, '/api/v1/register')
如果缺少请求参数, 会直接返回400 BAD REQUEST
POST http://127.0.0.1:5000/api/v1/register HTTP/1.1
User-Agent: Fiddler
Host: 127.0.0.1:5000
Content-Type: application/json
Content-Length: 29
{
"username": "test8"
}
HTTP/1.1 400 BAD REQUEST
Server: Werkzeug/2.2.2 Python/3.8.5
Date: Thu, 01 Sep 2022 11:04:48 GMT
Content-Type: application/json
Content-Length: 70
Connection: close
{
"message": {
"password": "password is required"
}
}
help 值
指定参数,添加help
# 校验入参
parser = reqparse.RequestParser()
parser.add_argument('username', required=True, type=str, help='username is required')
parser.add_argument('password', required=True, type=str, help='password is required')
args = parser.parse_args()
如果你指定了 help 参数的值,在解析的时候当类型错误被触发的时候,它将会被作为错误信息给呈现出来。如果你没有指定 help 信息的话,默认行为是返回类型错误本身的信息。
正如上面接口看到的,缺少password参数,接口返回
HTTP/1.1 400 BAD REQUEST
Server: Werkzeug/2.2.2 Python/3.8.5
Date: Thu, 01 Sep 2022 11:04:48 GMT
Content-Type: application/json
Content-Length: 70
Connection: close
{
"message": {
"password": "password is required"
}
}
required=True 必需的参数
如果这个参数是必选项,那么只需要添加 required=True 来调用 add_argument()
parser.add_argument('username', required=True, type=str, help='username is required')
多个值&列表
如果你要接受一个键有多个值的话,你可以传入 action='append'
parser.add_argument('name', type=str, action='append')
你的参数将会像这样
args = parser.parse_args()
args['name'] # ['bob', 'sue', 'joe']
其它目标(Destinations)
如果由于某种原因,你想要以不同的名称存储你的参数一旦它被解析的时候,你可以使用 dest kwarg。
parser.add_argument('name', type=str, dest='public_name')
args = parser.parse_args()
args['public_name']
参数位置
默认下,RequestParser 试着从 flask.Request.values,以及 flask.Request.json 解析值。
在 add_argument() 中使用 location 参数可以指定解析参数的位置。flask.Request 中任何变量都能被使用。例如:
# Look only in the POST body
parser.add_argument('name', type=int, location='form')
# Look only in the querystring
parser.add_argument('PageSize', type=int, location='args')
# From the request headers
parser.add_argument('User-Agent', type=str, location='headers')
# From http cookies
parser.add_argument('session_id', type=str, location='cookies')
# From file uploads
parser.add_argument('picture', type=werkzeug.datastructures.FileStorage, location='files')
多个位置
通过传入一个列表到 location 中可以指定 多个 参数位置:
parser.add_argument('text', location=['headers', 'values'])
列表中最后一个优先出现在结果集中。(例如:location=[‘headers’, ‘values’],解析后 ‘values’ 的结果会在 ‘headers’ 前面)
继承解析
往往你会为你编写的每个资源编写不同的解析器。这样做的问题就是如果解析器具有共同的参数。
不是重写,你可以编写一个包含所有共享参数的父解析器接着使用 copy() 扩充它。你也可以使用 replace_argument() 覆盖父级的任何参数,或者使用 remove_argument() 完全删除参数。
例如:
from flask.ext.restful import RequestParser
parser = RequestParser()
parser.add_argument('foo', type=int)
parser_copy = parser.copy()
parser_copy.add_argument('bar', type=int)
# parser_copy has both 'foo' and 'bar'
parser_copy.replace_argument('foo', type=str, required=True, location='json')
# 'foo' is now a required str located in json, not an int as defined
# by original parser
parser_copy.remove_argument('foo')
# parser_copy no longer has 'foo' argument