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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM