Json Schema簡介


1. 引言

什么是Json Schema? 以一個例子來說明

假設有一個web api,接受一個json請求,返回某個用戶在某個城市關系最近的若干個好友。一個請求的例子如下:

{
    "city" : "chicago", 
    "number": 20, 
    "user" : {
        "name":"Alex", 
        "age":20
        }
}

在上面的例子中,web api要求提供city,number,user三個成員,其中city是字符串,number是數值,user是一個對象,又包含了name和age兩個成員。

對於api來說,需要定義什么樣的請求合法,即什么樣的Json對於api來說是合法的輸入。這個規范可以通過Json Schema來描述,對應的Json Schema如下。

{ 
    "type": "object",
    "properties": {
        "city": { "type": "string" },
        "number": { "type": "number" },
        "user": { 
            "type": "object",
            "properties": {
                "name" : {"type": "string"},
                "age" : {"type": "number"}
            }                       
        }
    }
}

例子可以通過Json Schema Validator來驗證。

什么是Json Schema?

Json Schema定義了一套詞匯和規則,這套詞匯和規則用來定義Json元數據,且元數據也是通過Json數據形式表達的。Json元數據定義了Json數據需要滿足的規范,規范包括成員、結構、類型、約束等。

本文后面的部分是簡要介紹Json Schema定義的這些規則,以及如何用這些規則描述規范。

Json Schema定義了一系列關鍵字,元數據通過這些關鍵字來描述Json數據的規范。其中有些關鍵字是通用的;有些關鍵字是針對特定類型的;還有些關鍵字是描述型的,不影響合法性校驗。本文的主要內容就是介紹這些關鍵字的應用。

2. 類型關鍵字

首先需要了解的是"type"關鍵字,這個關鍵字定義了Json數據需要滿足的類型要求。"type"關鍵字的用法如下面幾個例子:

  1. {"type":"string"}。規定了Json數據必須是一個字符串,符合要求的數據可以是

"Today is a good day."
"I love you"

  1. {"type" : "object"}。規定了Json數據必須是一個對象,符合要求的數據可以是

{"name" : "Alexander", "age" : 98}
{}

  1. {"type" : "number"}。規定了Json數據必須是一個數值,符合要求的數據可以是。Java Script不區分整數、浮點數,但是Json Schema可以區分。

2
0.5

  1. {"type": "integer"}。要求數據必須是整數。

2

  1. {"type" : "array"}。規定了Json數據必須是一個數組,符合要求的數據可以是

["abc", "cdf"]
[1, 2, 3]
["abc", 25, {"name": "Alexander"} ]
[]

  1. {"type" : "boolean"}。這個Json Schema規定了Json數據必須是一個布爾,只有兩個合法值

true
false

  1. {"type" : "null"}。null類型只有一個合法值

null

3. 簡單類型

這部分介紹類型特定的關鍵,包括字符串、數值、布爾、空值幾種基本類型。

3.1 字符串

Json合法的字符串

"Today is a good day."

對應的Json Schema

{"type": "string"}

可以進一步對字符串做規范要求。字符串長度匹配正則表達式字符串格式

3.1.1 字符串長度

關鍵字: minLength, maxLength

可以對字符串的最小長度、最大長度做規范。

{
    "type" : "string",
    "minLength" : 2,
    "maxLength" : 3,
}

3.1.2 正則表達式

關鍵字: pattern

可以對字符串應滿足的Pattern做規范,Pattern通過正則表達式描述。

{
    "type" : "string",
    "pattern" : "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$",
}

3.1.3 字符串Format

關鍵字: format

可以通過Json Schema內建的一些類型,對字符串的格式做規范,例如電子郵件、日期、域名等。

{
   "type" : "string",
   "format" : "date",
}

Json Schema支持的format包括"date", "time", "date-time", "email", "hostname"等。具體可以參考文檔

3.2 數值

Json Schema數值類型包括"number"和"integer"。number合法的數值可以是

2
0.1

對應的Json Schema為

{"type": "number"}

如果是integer則只能是整數。"number"和"integer"的類型特定參數相同,可以限制倍數范圍

3.2.1 數值滿足倍數

關鍵字: multipleOf

可以要求數值必須某個特定值的整數倍。例如要求數值必須是10的整數倍。

{
    "type" : "number",
    "multipleOf" : 10,
}

3.2.2 數值范圍

關鍵字: minimum, maximum, exclusiveMinimum, exclusiveMaximum

可以限制數值的方位,包括最大值、最小值、開區間最大值、開區間最小值。

要求數值在[0, 100)范圍內。

{
    "type" : "number",
    "minimum": 0,
    "exclusiveMaximum": 100
}

3.3 布爾

布爾類型沒有額外的類型特定參數。

3.4 空值

null類型沒有額外的類型特定參數。

4. 復合類型

復合類型可以通過Nest的方式構建復雜的數據結構。包括數組、對象。

4.1 數組

Json數組合法數據的例子

[1, 2, 3]
[1, "abc", {"name" : "alex"}]
[]

Json Schema為

{"type": "array"}

數組的類型特定參數,可以用來限制成員類型是否允許額外成員最小元素個數最大元素個數是否允許元素重復

4.1.1 數組成員類型

關鍵字: items

可以要求數組內每個成員都是某種類型,通過關鍵字items實現。下面的Schema要求數組內所有元素都是數值,這時關鍵字"items"對應一個嵌套的Json Schema,這個Json Schema定義了每個元素應該滿足的規范。

{
    "type": "array",
    "items": {
        "type": "number"
    }
}

[1, 2, 3]

關鍵字items還可以對應一個數組,這時Json數組內的元素必須與Json Schema內items數組內的每個Schema按位置一一匹配。

{
    "type": "array",
    "items": [
    {
        "type": "number"
    },
    {
        "type": "string"
    }]
}

[1, "abc"]

4.1.2 數組是否允許額外成員

關鍵字: additionalItems

當使用了items關鍵字,並且items關鍵字對應的是Schema數組,這個限制才起作用。關鍵字additionalItems規定Json數組內的元素,除了一一匹配items數組內的Schema外,是否還允許多余的元組。當additionalItems為true時,允許額外元素。

{
    "type": "array",
    "items": [
    {
        "type": "number"
    },
    {
        "type": "string"
    }],
    "additionalItems" : true
}

[1, "abc", "x"]

4.1.3 數組元素個數

關鍵字: minItems, maxItems

可以限制數組內元素的個數。

{
    "type": "array",
    "items": {
        "type": "number"
    },
    "minItems" : 5,
    "maxItems" : 10
}

[1,2,3,4,5,6]

4.1.4 數組內元素是否必須唯一

關鍵字: uniqueItems

規定數組內的元素是否必須唯一。

{
    "type": "array",
    "items": {
        "type": "number"
    },
    "uniqueItems" : true
}

[1,2,3,4,5]

4.2 對象

Json對象是最常見的Json數據類型,合法的數據可以是

{
    "name": "Froid",
    "age" : 26,
    "address" : {
        "city" : "New York",
        "country" : "USA"
    }
}

就對象類型而言,最基本的類型限制Schema是

{"type" : "object"}

然而,除了類型外,我們通常需要對其成員做進一步約定。對象的類型特定關鍵字,大多是為此目的服務的。

4.2.1 成員的Schema

關鍵字:properties

規定對象各成原所應遵循的Schema。

{ 
    "type": "object",     
    "properties": {      
        "name": {"type" : "string"},
        "age" : {"type" : "integer"},
        "address" : {
            "type" : "object",
            "properties" : {
                "city" : {"type" : "string"},
                "country" : {"type" : "string"}
            }
        }
    }
}

對於上例中的Schema,合法的data是

{
    "name": "Froid",
    "age" : 26,
    "address" : {
        "city" : "New York",
        "country" : "USA"
    }
}

properties關鍵字的內容是一個key/value結構的字典,其key對應Json數據中的key,其value是一個嵌套的Json Schema。表示Json數據中key對應的值所應遵守的Json Schema。在上面的例子中,"name"對應的Schema是{"type" : "string"},表示"name"的值必須是一個字符串。在Json數據中,對象可以嵌套,同樣在Json Schema中也可以嵌套。如"address"字段,在Json Schema中它的內容是一個嵌套的object類型的Json Schema。

4.2.2 批量定義成員Schema

關鍵字:patternProperties

與properties一樣,但是key通過正則表達式匹配屬性名。


{
    "type": "object",
    "patternProperties": {
        "^S_": { "type": "string" },
        "^I_": { "type": "integer" }
    }
}

{"S_1" : "abc"}
{"S_1" : "abc", "I_3" : 1}

4.2.3 必須出現的成員

關鍵字:required

規定哪些對象成員是必須的。

{ 
    "type": "object",     
    "properties": {      
        "name": {"type" : "string"},
        "age" : {"type" : "integer"},
    },
    "required" : ["name"]
}

上例中"name"成員是必須的,因此合法的數據可以是

{"name" : "mary", "age" : 26}
{"name" : "mary"}

但缺少"name"則是非法的

{"age" : 26}

4.2.4 成員依賴關系

關鍵字:dependencies

規定某些成員的依賴成員,不能在依賴成員缺席的情況下單獨出現,屬於數據完整性方面的約束。

{
    "type": "object",
    "dependencies": {
        "credit_card": ["billing_address"]
    }
}

dependencies也是一個字典結構,key是Json數據的屬性名,value是一個數組,數組內也是Json數據的屬性名,表示key必須依賴的其他屬性。

上面Json Schema合法的數據可以是

{}
{"billing_address" : "abc"}

但如果有"credit_card"屬性,則"billing_address" 屬性不能缺席。下面的數據是非法的

{"credit_card": "7389301761239089"}

4.2.5 是否允許額外屬性

關鍵字:additionaProperties

規定object類型是否允許出現不在properties中規定的屬性,只能取true/false。

{ 
    "type": "object",     
    "properties": {      
        "name": {"type" : "string"},
        "age" : {"type" : "integer"},
    },
    "required" : ["name"],
    "additionalProperties" : false
}

上例中規定對象不能有"name"和"age"之外的成員。合法的數據

{"name" : "mary"}
{"name" : "mary", "age" : 26}

非法的數據

{"name" : "mary", "phone" : ""84893948}

4.2.6 屬性個數的限制

關鍵字:minProperties, maxProperties

規定最少、最多有幾個屬性成員。


{
    "type": "object",
    "minProperties": 2,
    "maxProperties": 3
}

{"name" : "mary", "age" : 26}
{"name" : "mary", "age" : 26, "phone" : "37839233"}

5. 邏輯組合

關鍵字:allOf, anyOf, oneOf, not

從關鍵字名字可以看出其含義,滿足所有、滿足任意、滿足一個。前三個關鍵字的使用形式是一致的,以allOf為例說明其形式。

{
    "allOf" : [
        Schema1,
        Schema2,
        ...
    ]
}

其中,"allOf"的內容是一個數組,數組內的成員都是內嵌的Json Schema。上例Schema1、Schema2都是內嵌的Json Schema。整個Schema表示當前Json數據,需要同時滿足Schema1、Schema2,。

5.1 allOf

滿足allOf數組中的所有Json Schema。

{
    "allOf" : [
        Schema1,
        Schema2,
        ...
    ]
}

需要注意,不論在內嵌的Schema里還是外部的Schema里,都不應該使"additionalProperties"為false。否則可能會生成任何數據都無法滿足的矛盾Schema。

可以用來實現類似“繼承”的關系,例如我們定義了一個Schema_base,如果想要對其進行進一步修飾,可以這樣來實現。

{
    "allOf" : [
        Schema_base
    ]
    "properties" : {
        "other_pro1" : {"type" : "string"},
        "other_pro2" : {"type" : "string"}
    },
    "required" : ["other_pro1", "other_pro2"]
}

Json數據既需要滿足Schema_base,又要具備屬性"other_pro1"、"other_pro2"。

5.2 anyOf

滿足anyOf數組中的任意個Schema。

{
    "anyOf" : [
        Schema1,
        Schema2,
        ...
    ]
}

Json數據需要滿足Schema1、Schema2中的一個或多個。

5.3 oneOf

滿足且進滿足oneOf數組中的一個Schema,這也是與anyOf的區別。

{
    "oneOf" : [
        Schema1,
        Schema2,
        ...
    ]
}

5.4 not

這個關鍵字不嚴格規定Json數據應滿足什么要求,它告訴Json不能滿足not所對應的Schema。

{
    "not" : {"type" : "string"}
}

只要不是string類型的都Json數據都可以。

6. 復雜結構

對復雜結構的支持包括定義和引用。可以將相同的結構定義成一個“類型”,需要使用該“類型”時,可以通過其路徑或id來引用。

6.1 定義

關鍵字:無

定義一個類型,並不需要特殊的關鍵字。通常的習慣是在root節點的definations下面,定義需要多次引用的schema。definations是一個json對象,key是想要定義的“類型”的名稱,value是一個json schema。

{
    "definitions": {
        "address": {
            "type": "object",
            "properties": {
                "street_address": { "type": "string" },
                "city":           { "type": "string" },
                "state":          { "type": "string" }
            },
            "required": ["street_address", "city", "state"]
        }
    },
    "type": "object",
    "properties": {
        "billing_address": { "$ref": "#/definitions/address" },
        "shipping_address": { "$ref": "#/definitions/address" }
    }
}

上例中定義了一個address的schema,並且在兩個地方引用了它,#/definitions/address表示從根節點開始的路徑。

6.2 $id

關鍵字:$id

可以在上面的定義中加入\(id屬性,這樣可以通過\)id屬性的值對該schema進行引用,而不需要完整的路徑。

...
    "address": {
            "type": "object",
            "$id" : "address",
            "properties": {
                "street_address": { "type": "string" },
                "city":           { "type": "string" },
                "state":          { "type": "string" }
            },
            "required": ["street_address", "city", "state"]
        }
...

6.3 引用

關鍵字:$ref

關鍵字$ref可以用在任何需要使用json schema的地方。如上例中,billing_address的value應該是一個json schema,通過一個$ref替代了。

$ref的value,是該schema的定義在json中的路徑,以#開頭代表根節點。

{
    "properties": {
        "billing_address": { "$ref": "#/definitions/address" },
        "shipping_address": { "$ref": "#/definitions/address" }
    }
}

如果schema定義了$id屬性,也可以通過該屬性的值進行引用。

{
    "properties": {
        "billing_address": { "$ref": "#address" },
        "shipping_address": { "$ref": "#address" }
    }
}

7. 通用關鍵字

通用關鍵字可以在任何json schema中出現,有些影響合法性校驗,有些只是描述作用,不影響合法性校驗。

7.1 enum

關鍵字:enum

可以在任何json schema中出現,其value是一個list,表示json數據的取值只能是list中的某個。


{
    "type": "string",
    "enum": ["red", "amber", "green"]
}

上例的schema規定數據只能是一個string,且只能是"red"、"amber"、"green"之一。

7.2 metadata

關鍵字:title,description,default,example

{
    "title" : "Match anything",
    "description" : "This is a schema that matches anything.",
    "default" : "Default value",
    "examples" : [
        "Anything",
        4035
    ]
}

只作為描述作用,不影響對數據的校驗。


免責聲明!

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



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