在 Python 中檢查 JSON 結構
最近在用改寫一個用 Python 寫的小工具,這個工具主要是為了讓某些日常作業可以自動化。程式中有一個部分,是從 AWS Secret Manager 上取得格式為 JSON 的敏感資料,在讀取這個資料之前,會先對資料的結構進行檢查,之前的做法是使用斷定:
data = {
"username": "Allen",
"email": "allen@email.com",
}
assert "username" in data, "username missing!"
assert "email" in data, "email missing!"雖然這個方法也行得通,但如果是較為複雜的資料結構,那我就會有寫不完的斷定了,日後在閱讀上也很不直觀。
此時我想到 Laravel 在測試上有提供一個很方便的語法,可以用來檢查 API 回傳的 JSON 結構。
test('we can get the latest posts', function () {
Post::factory(6)->create();
get(route('api.posts'))
// 斷定 API 回傳的 JSON 結構
->assertJsonStructure([
'data' => [
'*' => ['id', 'title', 'excerpt', 'created_at', 'updated_at', 'url'],
],
])
->assertSuccessful();
});這讓我不禁開始想,Python 當中有沒有類似的工具可以用來檢查 JSON 的結構?
簡單的 Google 與詢問 AI 之後,只能說 Python 不愧是全世界最流行的語言之一,我的疑問完全是多餘的,有一個 Python 套件 jsonschema 可以很輕鬆的做到這件事情。
安裝套件
我們可以使用 pip 指令安裝 jsonschema。
pip install jsonschema
# 使用 uv
uv python install 3.14
uv add jsonschema基本使用方式
jsonschema 的使用方式相當簡單,首先使用 Python 的字典(Dictionary)定義好預期的 JSON 結構後,我們就可以使用 validate() 函式來檢查目標資料的結構是否符合我們定義好的結構。如果未符合,函式就會拋出一個例外。
from jsonschema import validate, ValidationError
# 定義預期的資料結構
schema = {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "number"},
},
}
data = {
"name": "Allen",
"age": 30,
}
try:
# 判斷 data 的結構是否與 schema 的相同
# 如果與 schema 不同,就會拋出例外
validate(instance=data, schema=schema)
print("Validation successful")
except ValidationError as e:
print(f"Validation failed: {e}")定義結構
在結構定義中,我們需要先使用 type 定義我們預期的型別,以簡單的字串、數字、列表與物件為例。
# 定義一個字串
schema = {
"type": "string",
}
data = "allen"# 定義一個數字
schema = {
"type": "number",
}
data = 30# 定義一個列表
schema = {
"type": "array",
"items": { "type": "number" }
}
data = [1, 2, 3, 4]# 定義一個物件
schema = {
"type": "object",
"properties": {
"username": { "type": "string" }
"age": { "type": "number" }
}
}
data = {
"username": "allen"
"age": 30
}jsonschema 提供豐富的選項來定義 JSON 結構。除了判斷型別之外,我們還可以檢查數字的大小以及字串的長度,甚至可以透過正則表達式來檢查字串的格式。
schema = {
"type": "object",
"properties": {
"username": {"type": "string", "minLength": 3, "maxLength": 20},
"email": {"type": "string", "pattern": r"^\S+@\S+\.\S+$"},
"age": {"type": "number", "minimum": 0, "maximum": 120},
},
}如果是列表型別,也可以檢查列表的長度與是否包含重複的資料。
schema = {
"type": "array",
"items": {"type": "number"},
"minItems": 1,
"maxItems": 10,
"uniqueItems": True,
}需要注意的是,資料結構的鍵值(Key)預設是可選的,如果我們希望這個鍵值是必要的,就需要在 required 中標註。
schema = {
"type": "object",
"properties": {
"username": {"type": "string", "minLength": 3, "maxLength": 20},
"email": {"type": "string", "pattern": r"^\S+@\S+\.\S+$"},
"age": {"type": "number", "minimum": 0, "maximum": 120},
},
# username 與 email 一定要存在
"required": ["username", "email"]
}結合前面的例子,我們就可以來定義較為複雜,甚至是多階層的資料結構。
schema = {
"type": "object",
"properties": {
"id": {"type": "number"},
"user": {
"type": "object",
"properties": {
"name": {"type": "string"},
"email": {"type": "string"}
},
"required": ["name"]
}
},
"required": ["id", "user"]
}如果你跟我一樣還在使用很多斷定來檢查資料結構,不妨考慮看看 jsonschema 這個套件!不只易用,也能增加程式碼的可讀性。
最近開始在自己的 Python 專案中陸續使用 jsonschema,誠心推薦。