jsonlint:python的json資料驗證庫

dockerdog發表於2019-02-16

隨著前後端分離和 REST APIs 的火熱,開發者不斷尋找著一種靈活的、優雅的方式驗證 json 資料。有直接手動獲取資料驗證的,也有使用 json scheme 驗證的。前者容易使得函式變得冗長,還可能存在不少重複的驗證;後者驗證又不靈活。

本文介紹的 jsonlint 啟發自 python 的表單驗證工具 wtforms,wtforms 通過繼承 Form 類也能進行 json 資料驗證,但是 wtforms 對於 json 的陣列(Array)型別處理有著很詭異的行為,需要通過 a-1 、 a-2 這樣來傳遞陣列資料,常常不能有效的處理陣列資料。 jsonlint 大部分程式碼來著 wtforms,可以視為 wtforms 的一個分支。但 jsonlint 刪去了 wtforms 的表單渲染部分,更改了傳入的資料格式,最重要的是使用正確的邏輯驗證陣列(Array)和物件(Object)型別。下面是一些例子:

基本的字串型別json驗證

對於基本的字串型別,我們只需要建立一個 Json 的子類,填寫對應的 Field 即可。使用方式和 wtforms 型別:

from jsonlint import Json
from jsonlint.fields import StringField
from jsonlint.validators import DataRequired

class MyLint(Json):
    name = StringField(validators=[DataRequired()])

mylint = MyLint({`name`: `demo`})
print mylint.validate()  # True
print mylint.name.data  # demo

更靈活的驗證 json 資料

jsonlint 繼承了 wtforms 的優點,可以進行一些更靈活的自定義json資料驗證,只要將 field 類的例項名寫成函式 validate_fieldname ,即可自定義驗證改欄位:

from jsonlint import Json
from jsonlint.fields import IntegerField
from jsonlint.validators import ValidationError

class AgeLint(Json):
    age = IntegerField()

    def validate_age(form, field):
        if field.data < 13:
            raise ValidationError("We`re sorry, you must be 13 or older to register")

agelint = AgeLint({`age`: 12})
print agelint.validate()  # False
print agelint.age.errors  # ["We`re sorry, you must be 13 or older to register"]

對陣列型別進行驗證

jsonlint 誕生可以說主要就是為了解決如何驗證陣列型別的問題,在jsonlint這很容易實現:

from jsonlint import Json
from jsonlint.fields import StringField, ListField
from jsonlint.validators import DataRequired, ValidationError

class ListLint(Json):
    cars = ListField(StringField(validators=[DataRequired()]))

    def validate_cars(form, field):
        if `BMW` in field.data:
            raise ValidationError("We`re sorry, you cannot drive BMW")

listlint = ListLint({`cars`: [`Benz`, `BMW`, `Audi`]})
print listlint.validate()  # False
print listlint.cars.errors  # ["We`re sorry, you cannot drive BMW"]

ListField 類作為一個 Field 容器,容納其它型別 Field 的陣列,將對應型別的陣列直接傳入,即可有效的驗證;ListField 同樣也可以進行自定義驗證。

對物件型別進行驗證

物件型別在一些 REST APIs 的 web 應用中也經常存在,對此 jsonlint 也作了支援。只要將 Json 子類傳入 ObjectField 中即可進行驗證:

from jsonlint import Json
from jsonlint.fields import ObjectField, IntegerField, BooleanField

class T(Json):
    status = BooleanField()
    code = IntegerField()

class DataLint(Json):
    data = ObjectField(T)

datalint = DataLint({`data`: {`status`: True, `code`: 200}})
print datalint.validate()  # False
print datalint.data.code.data  # 200

寫在最後

jsonlint 誕生初衷就是因為本人想用類似 wtforms 的方式來驗證json,這樣不但有著良好的驗證方式,還可以分割業務,避免介面主函式變得十分冗長。例如,可以定義類:

class RegisterLint(UserLint):
    def validata_nickname(self, field):
        ...

    def validate_account(self, field):
        ...

    def create_user(self):
        ...

user = RegisterLint()

這樣既可以使用 RegisterLint 的例項 user 驗證資料,同時又能直接執行 user.create_user() 進行資料庫操作,將資料庫邏輯更好的封裝。這樣可以說是在 MVC 設計模式的基礎上獨立出了一層。

想要嘗試使用 jsonlint 可以直接使用 pip 安裝:

pip install jsonlint

最後,jsonlint 開源在 Github : https://github.com/tangwz/jso…

jsonlint 現階段僅由我一人維護,雖然單元測試覆蓋率儘可能的全覆蓋,但也不代表沒有bug,希望您提出您寶貴的意見,或一起維護、迭代jsonlint:https://github.com/tangwz/jso…

如果使用 Flask 進行 web 開發,也可以使用封裝好的結合了 Flask 和 jsonlint 的庫: Flask-Lint

原文地址:http://tangwz.com/2017/11/28/…

相關文章