Python Web参数校验库之webargs

Python Web参数校验库之webargs

用Python做Web后端开发的同学想必都知道,如何快速解析和校验前端传递过来的请求参数是代码中必不可少的任务。

以flask为例

@app.route("/api/login", methods=["POST"])
def login():
    data = request.get_json()
    # 邮箱格式校验
    email = data.get("email")
    if not email or re.match(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)", email):
        return jsonify({"code": 400, "msg": "参数有误"}), 400
    # 密码长度校验
    password = data.get("password")
    if not password or len(password) < 6:
        return jsonify({"code": 400, "msg": "参数有误"}), 400
    # 数据库查询
    return jsonify({"code": 200, "msg": "ok"})

对于一个简单的登录接口,要写一堆又臭又长的参数校验逻辑,而这些本是和业务逻辑没什么关系的代码。

只要是和业务无关的代码,我们总能找到一些框架或者库来解决问题,而针对web请求参数的解析和校验库, webargs 就是一款强大的工具。它直接站在巨人的肩膀上,基于marshmallow做了字段规则校验工作,如果熟悉 marshmallow 的同学上手这个库也就半小时。

另一个特点是它针对市面上常见的web框架都写了一个单独的解析器parser,对开发者来说无疑是真香,不管你用的是哪个web框架,都能无缝接入webargs到项目中,无需我们自己做过多封装。

安装

$ pip install -U webargs

使用

from webargs import fields
from webargs.flaskparser import use_args

app = Flask("hello")


@app.route("/api/login", methods=["POST"])
@use_args({"username": fields.Str(required=True),
           "password": fields.Str(required=True, validate=lambda x: len(x) >= 6)})
def login(args):
    name = args['username']
    password = args['password']
    return jsonify({"code": 200, "msg": "ok"})

use_args 是 webargs 提供的装饰器,正是有了这个装饰器,它能处理前端传过来的请求参数,我们只要定义好schema,剩下的交给webargs。

所谓 schema 就是你希望前端传过来的参数有哪些,每个参数的类型是什么,应该满足什么规则等等。

这里我们定义的schema要求usename字段必须是字符串,而且是必填项, password 的长度必须大于6.

如果你用的是django,只需要导入djangoparser下的use_args 即可

from webargs.djangoparser import use_args

如果用户没有按照要求发送数据,代码压根就不会执行到我们的业务代码中去,直接在装饰器就把错误返回给上层了,所以代码整洁了不少。

如果传的参数不符合要求,默认返回的错误码是422。但是返回的错误信息似乎看不懂,api的调用者看了并不知道参数错在哪里。

我们可以专门针对错误重新处理一下,同样返回一个格式可读的json体给前端, 这是flask的特性,如果是django,请自行查找相应的方法

@app.errorhandler(422)
@app.errorhandler(400)
def handle_error(err):
    headers = err.data.get("headers", None)
    messages = err.data.get("messages", ["Invalid request."])
    if headers:
        return jsonify({"errors": messages}), err.code, headers
    else:
        return jsonify({"errors": messages}), 400

location

webargs 默认情况下是从请求body中以json格式来读取和解析参数的,如果要通过其他方式获取,就需要指定在use_args中指定location

@app.route("/", methods=["GET"])
@use_args({"name": fields.Str(missing="Friend")}, location="querystring")
def index(args):
    """A welcome page."""
    return jsonify({"message": "Welcome, {}!".format(args["name"])})

location可支持的类型有:

  • 'querystring':通过url后面的查询参数获取
  • 'json' # 把请求body当作json来获取参数
  • 'form' # 通过form表单获取参数
  • 'headers' # 通过请求头获取参数
  • 'cookies' # 通过cookie获取
  • 'files' # 通过文件获取

验证器

webargs 最强大的地方其实还在Field提供的校验规则,依赖于marshmallow,我们可以指定每个字段的数据类型,支持的类型非常多。大部分都是marshmallow提供了,webargs自己也提供了部分字段类型。

除了可以指定具体的类型外,我们还可以指定验证器来要求字段符合某种规则, validate 接收的参数是函数,意味着我们可以自定义任何规则。

def must_exist_in_db(val):
    if val != 1:
        raise ValidationError("id not exist")


hello_args = {"name": fields.Str(missing="Friend"),
              "id": fields.Integer(required=True, validate=must_exist_in_db)}


@app.route("/", methods=["GET"])
@use_args(hello_args, location="query")
def hello(args):
    """A welcome page."""
    return jsonify({"message": "Welcome, {}!".format(args["name"])})

先介绍这么多,更多高级功能参考:https://webargs.readthedocs.io/en/latest/quickstart.html

赶紧在你的项目中试试吧!

posted @ 2022-03-15 23:16  公众号海哥python  阅读(1238)  评论(0编辑  收藏  举报