Python module - jsonschema Part 2

Posted on  Mar 23, 2018  in  Python 模組/套件推薦  by  Amo Chen  ‐ 4 min read

本文為 Python module - jsonchema 一系列教學文:

上一篇 Python module - jsonschema Part 1 中,介紹了 JSON Schema 的 6 種資料型別與驗證 JSON Schema 的方法。

本篇將會更進一步介紹幾種型別( number , string , array , object )更複雜的用法。

整數(integer)型別

number 包含任意正負數與小數,如果 JSON shema 要定義只接受整數的話,可以把 type 指定為 integer ,例如以下範例用 integer 型別驗證帶有小數點的數字就會驗證失敗:

from jsonschema import validate

schema = {'type': 'integer'}

# would raise exception
validate(123.123, schema)

執行結果:

ValidationError: 123.123 is not of type 'integer'

Failed validating 'type' in schema:
    {'type': 'integer'}

On instance:
    123.123

限定數值範圍

JSON Schema 能夠限定數值的範圍,其關鍵字有 minimum maximum exclusiveMinimum exclusiveMaximum

以下範例為限定數值只能在 1 至 10 之間(包含 1 與 10) :

schema = {
    'type': 'number',
    'minimum': 1,
    'maximum': 10
}

如果要不包含 1 與 10 ,則可以再加上 exclusiveMinimum exclusiveMaximum 2 個關鍵字,例如以下範例,帶入 1 或 10 都會無法通過驗證:

schema = {
    'type': 'number',
    'minimum': 1,
    'exclusiveMinimum': True,
    'maximum': 10,
    'exclusiveMaximum': True,
}

限定字串(string)長度

預設 string 型別並沒有字串長度限制,但一般實際使用上字串會有長度限制,例如留言板的留言不能超過 1024 字,最少要 1 個字,我們可以在 JSON Schema 上加上限制字串長度:

shema = {
    'type': 'string',
    'minLength': 1,
    'maxLength': 1024,
}

上述的範例即是使用 minLengthmaxLength 限制字串的最小與最長長度。

字串的正規表示式

利用正規表示式驗證字串也是很常見的方式, JSON schema 也同樣支援正規表示式的用法,例如限制使用者帳號只能輸入英文與數字:

schema = {
    'type': 'sting',
    'pattern': '^[a-zA-Z0-9]+$',
}

正規表示式的關鍵字是 pattern ,正規表示式的更詳細語法可以參閱 Regular Expressions

內建的字串格式

Python 的 jsonschema 套件也實作 JSON Schema 中規範的幾種格式,例如 date-time email 等,可以多加利用。以下為使用 format 關鍵字驗證 email 的範例:

import jsonschema

schema = {
    'type': 'string',
    'format': 'email',
}

jsonschema.validate(
    '[email protected]',
    schema,
    format_checker=jsonschema.FormatChecker()
)

上述範例中的 format_checker=jsonschema.FormatChecker() 是必須的,如果沒有使用該參數, jsonschema 套件就只會檢查資料是否為 string 型別而已。

而 jsonschema 套件也提供客製化 FormatChecker() 的方法,詳情可以參閱 Validating Formats ,相關支援的 format 也可以在該文件中找到。

限定 array 的長度

array 型別預設也沒有長度限制,一般使用上也會有長度的限制,例如月份最多就是 12 個月,因此可以透過 minItemsmaxItems 2 個關鍵字為 array 加上長度的最小或最長限制:

schema = {
    'type': 'array',
    'minItems': 1,
    'maxItems': 12,
}

限定 array 內的元素不可重複

如果要限定 array 內的元素不可重複,只需要加上 'uniqueItems': True 即可。

schema = {
    'type': 'array',
    'uniqueItems': True
}

p.s. []array 也會通過驗證

指定 array 內的元素型別

array 提供 items 關鍵字,可以讓我們指定每一個元素的型別,例如指定 array 內的每個元素都必須是 string

schema = {
    'type': 'array',
    'items': {
        'type': 'string',
    }
}

# would pass
validate(['a', 'b', 'c'], schema)

# would raise exception
validate(['a', 2, 'c'], schema)

執行結果:

ValidationError: 2 is not of type 'string'

Failed validating 'type' in schema['items']:
    {'type': 'string'}

On instance[1]:
    2

上述範例中 validate(['a', 'b', 'c'], schema) 會通過驗證,而 validate(['a', 2, 'c'], schema) 則是無法通過驗證,原因在於其中一個元素 2 不是 string 型別。

如果陣列內的每一個元素型別不一樣,可以使用 Tuple validation 按照次序分別指定每個元素的型別:

schema = {
    'type': 'array',
    'minItems': 3,
    'maxItems': 3,
    'items': [
        {'type': 'string'},
        {'type': 'number'},
        {'type': 'integer'}
    ]
}

上述範例就必須代入長度為 3 且元素依序分別為 string number integer 的型別(例如: ['a', 1.1, 1] )才能通過驗證,

限定 object 的屬性( Properties

object 預設並沒有限定屬性(property),因此只要是 object 都會通過驗證,但一般使用 object 時都會有特定的屬性,例如存放使用者資料的 object 必須有 name , gender , email 3 個屬性,其 JSON Schema 會如以下範例:

schema = {
    'type': 'object',
    'properties': {
        'name': {'type': 'string'},
        'gender': {'type': 'string'},
        'email': {'type': 'string'},
    },
    'required': [
        'name',
        'gender',
        'email'
    ]
}

上述範例用 properties 關鍵字指定 object 內的屬性有 name, gender, email 3 個,但因為預設這些 properties 都是 optional 的,因此額外加上 required 關鍵字,指定 name, gender, email 都是必要屬性,只要 object 資料內沒有這些屬性就會驗證失敗,例如以下少了 email 的 object 會驗證失敗:

# would pass
validate(
    {
        'name': 'foo',
        'gender': 'male',
        'email': '[email protected]'
    },
    schema
)

# would raise exception
validate(
    {
        'name': 'foo',
        'gender': 'male'
    },
    schema
)

此外,假設屬性都滿足 JSON Schema 的設定時,如果資料內有多餘的屬性也會通過驗證,例如上述範例除了 name, gender, email 如果額外加上任意屬性也會通過驗證:

# would pass
validate(
    {
        'name': 'foo',
        'gender': 'male',
        'email': '[email protected]',
        'account': 'bar',
    },
    schema
)

如果要將 object 內存在額外屬性視為格式錯誤的話,可以加上 'additionalProperties': False 讓額外的屬性不被允許。

The additionalProperties keyword is used to control the handling of extra stuff, that is, properties whose names are not listed in the properties keyword. By default any additional properties are allowed.

因此上述的 scheam 會變成:

schema = {
    'type': 'object',
    'properties': {
        'name': {'type': 'string'},
        'gender': {'type': 'string'},
        'email': {'type': 'string'},
    },
    'required': [
        'name',
        'gender',
        'email'
    ],
    'additionalProperties': False,
}

小結

本篇介紹 number , string , array , object 幾種型別較複雜的用法,下一篇將介紹如何進一步同時混用多種型別,以驗證更加複雜的 JSON 資料格式。

References

https://spacetelescope.github.io/understanding-json-schema/

對抗久坐職業傷害

研究指出每天增加 2 小時坐著的時間,會增加大腸癌、心臟疾病、肺癌的風險,也造成肩頸、腰背疼痛等常見問題。

然而對抗這些問題,卻只需要工作時定期休息跟伸展身體即可!

你想輕鬆改變現狀嗎?試試看我們的 PomodoRoll 番茄鐘吧! PomodoRoll 番茄鐘會根據你所設定的專注時間,定期建議你 1 項辦公族適用的伸展運動,幫助你打敗久坐所帶來的傷害!

贊助我們的創作

看完這篇文章了嗎? 休息一下,喝杯咖啡吧!

如果你覺得 MyApollo 有讓你獲得實用的資訊,希望能看到更多的技術分享,邀請你贊助我們一杯咖啡,讓我們有更多的動力與精力繼續提供高品質的文章,感謝你的支持!