zoukankan      html  css  js  c++  java
  • python项目使用jsonschema进行参数校验

    python项目使用jsonschema进行参数校验

    最近想要给一个新的openstack项目加上参数校验,过完年回来准备开工的时候,发现其他人已经在做了,对应的patch是:https://review.openstack.org/#/c/422547/

    作者写的很棒,但是对比nova的实现还有一些不足,这里记一下学习笔记

    参数校验这个功能,作者大致的实现思路很明确,通过装饰器进行,是这样

    @check_input(参数)
    def post():
        pass
    
    def check_input(参数):
    
        def wrapper(f):
            ## check
            f()
    
        return wrapper
    

    作者选用jscon schem进行参数校验,jsonschem的一个使用方式如下:

    from jsonschema.validators import Draft4Validator
    #这里的schem表示至少两个布尔变量
    validator = Draft4Validator(
       schema={"items": {"type": "boolean"}, "minItems": 2},)
    validator.validate([True, False])
    validator.validate([True, True, True])
    

    根据这个继续完善之前的代码

    post_schem = {...}
    validator = Draft4Validator(schem=post_schem)
    @check_input(validator,request)
    def post():
        pass
    
    def check_input(参数):
    
        def wrapper(f):
            validator.validate(request.json)
            f()
    
        return wrapper
    

    大概的逻辑是这样了,我们会有不同的参数,所以要把参数管理起来,所以作者写了一个单独的schemas.py 来管理所有schema

    flavor_schema = {...}
    jsonschema.Draft4Validator.check_schema(flavor_schema)
    SCHEMAS = {'flavor_schema': flavor_schema}
    

    作者为了更方便地使用validator,写了新的valiator

    #validator.py
    class Validator(object):
        def __init__(self, name):
            self.name = name
            self.schema = schemas.SCHEMAS.get(name)
            checker = jsonschema.FormatChecker()
            self.validator = validators.Draft4Validator(self.schema,
                                                    format_checker=checker)
    
        def validate(self, data):
            try:
                self.validator.validate(data)
            except jsonschema.ValidationError as ex:
                LOG.exception(ex.message)
                # TODO(ramineni):raise valence specific exception
                raise Exception(ex.message)
    

    最终的check_input函数实现:

    ##validator.py
    def check_input(validator, request):
        def decorated(f):
            @wraps(f)
            def wrapper(*args, **kwargs):
                data = request.json
                LOG.debug("validating input %s with %s", data, validator.name)
                validator.validate(data)
                ##这里看起来有个bug,应该是f(*args, **kwargs),未测试
                return f()
            return wrapper
        return decorated
    
    

    这样通过下面的方式就可以进行参数校验了:

    import validator
    flavor_validator = validator.Validator('flavor_schema')
    @validator.check_input(flavor_validator, request)
    
    

    作者写的很好,但是个人觉得名叫validator的变量实在太多了,看的很糊涂。

    看了下nova项目的validator实现,思路也是类似的,但是写的更漂亮了,使用起来也比这个更简单了,下面是nova中check_input函数的实现,区别在于不需要先构建validator再使用装饰器,validator在装饰器执行的过程中构建,代码更简洁优雅。另外使用kwargs['body']而不是request.json, 所以也不需要传入request。

    def schema(request_body_schema, min_version=None, max_version=None):
    
        def add_validator(func):
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                #在_schema_validation_helper函数中构建了validator
                _schema_validation_helper(request_body_schema, kwargs['body'],
                                          min_version, max_version,
                                          args, kwargs)
                return func(*args, **kwargs)
            return wrapper
    
        return add_validator
    
  • 相关阅读:
    JavaScript创建对象
    php 用户访问菜单页面,必须登录,判断用户是否登录
    ThinkPHP 3.1.2 控制器的模块和操作
    商业智能数据营销该怎么做?
    HTML::Entities 编码或解码 HTML 实体的字符串
    perl 处理json 数组格式
    打开redis服务提示
    Windwos 08R2_DNS+AD安装图文
    Windwos 08R2_DNS+AD安装图文
    单选按钮和标签组合点击
  • 原文地址:https://www.cnblogs.com/zhangyufei/p/6398489.html
Copyright © 2011-2022 走看看