Hi im jaychung

I am still me as long as my spirit is free.

Load Complex JSON Schema with Python

最近拿 JSON schema 來驗證自己的 API 回傳內容有沒有錯誤,在過程中遇到一點小障礙─無法讀取複雜的 JSON schema

假設有支 API /v1/products/{product_id},它的 schema 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product resource",
"description": "A product resource",
"type": "object",
"additionalProperties": false,
"properties": {
"data": {
"type": "object",
"additionalProperties": false,
"properties": {
"product": {
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"price": {
"type": "integer"
},
"created_at": {
"type": "integer"
},
"updated_at": {
"type": "integer"
}
},
"required": [
"id",
"name",
"price",
"created_at",
"updated_at"
]
}
}
}
},
"required": [
"data"
]
}

這種簡單的 schema,直接用 json 讀取是沒問題的

1
2
3
4
import json

with open('specs/product-schema.json', 'r') as schema:
product_schema = json.loads(schema.read())

但總會有一些意料之外的事

如果今天有些 schema 會一直出現,你不想每個地方都重複寫一樣的東西,那你可能會需要 reference,而 File Reference 就是其中一種,像是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product resource",
"description": "A product resource",
"type": "object",
"additionalProperties": false,
"properties": {
"data": {
"type": "object",
"additionalProperties": false,
"properties": {
"product": {
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"price": {
"type": "integer"
},
"created_at": {
"$ref": "unix-timestamp.json"
},
"updated_at": {
"$ref": "unix-timestamp.json"
}
},
"required": [
"id",
"name",
"price",
"created_at",
"updated_at"
]
}
}
}
},
"required": [
"data"
]
}

created_atupdated_at 原本是 integer,但現在會 refer to unix-timestamp.json

這就無法直接用 json 完整的解析出來了,你可以自己寫一個 RefResolver,或是直接用 jsonref,懶人如我當然就是後者啦 XD

1
2
3
4
5
6
7
from os.path import json, dirname
import jsonref

base_uri = f'file:{join(dirname(__file__), "specs/")}'
with open('specs/product-schema.json', 'r') as schema:
product_schema = jsonref.loads(
schema.read(), base_uri=base_uri, jsonschema=True)

如此一來便能把整個 json 展開來,搭配 jsonschema 做 api validation

Proudly powered by Hexo and Theme by Hacker
© 2019 Jay Chung