1. JSON Schema
JSON Schema 是一種基于 JSON 的格式,用于描述 JSON 數(shù)據(jù)的結(jié)構(gòu)和驗(yàn)證 JSON 數(shù)據(jù)。它為 JSON 數(shù)據(jù)提供了一個(gè)清晰的描述,可以用來(lái)驗(yàn)證、文檔化,以及界定數(shù)據(jù)的接口。下面是 JSON Schema 的一些核心特點(diǎn)和應(yīng)用方式的詳細(xì)介紹:
- 描述數(shù)據(jù)格式:使用 JSON Schema,你可以詳細(xì)描述 JSON 數(shù)據(jù)的預(yù)期結(jié)構(gòu),包括哪些字段是必需的,字段的數(shù)據(jù)類(lèi)型是什么(如字符串、數(shù)字、布爾值等),以及字段的其他屬性(如字符串的最小長(zhǎng)度、最大長(zhǎng)度、正則表達(dá)式模式等)。
- 數(shù)據(jù)驗(yàn)證:JSON Schema 最常見(jiàn)的用途之一是驗(yàn)證 JSON 數(shù)據(jù)。這意味著你可以根據(jù)定義的 schema 來(lái)檢查 JSON 數(shù)據(jù)是否符合預(yù)期的格式,這在處理外部數(shù)據(jù)或 API 響應(yīng)時(shí)尤其有用。如果數(shù)據(jù)不符合預(yù)期,你可以捕獲這些錯(cuò)誤并相應(yīng)地處理它們。
- 自動(dòng)生成文檔:由于 JSON Schema 以標(biāo)準(zhǔn)化的格式描述了數(shù)據(jù)的結(jié)構(gòu),它可以被用來(lái)自動(dòng)生成文檔。這對(duì)于 API 的文檔化尤其有用,因?yàn)殚_(kāi)發(fā)者可以清晰地了解 API 接口期望接收什么樣的數(shù)據(jù),以及 API 響應(yīng)將返回什么樣的數(shù)據(jù)。
- 簡(jiǎn)化開(kāi)發(fā)流程:通過(guò)使用 JSON Schema 來(lái)驗(yàn)證數(shù)據(jù),開(kāi)發(fā)者可以減少手動(dòng)編寫(xiě)用于數(shù)據(jù)驗(yàn)證的代碼量。這不僅可以提高開(kāi)發(fā)效率,還可以減少由于數(shù)據(jù)錯(cuò)誤導(dǎo)致的 bug。
- 跨語(yǔ)言支持:JSON Schema 有廣泛的編程語(yǔ)言支持,包括但不限于 JavaScript、Python、Java 和 C#。這意味著無(wú)論你使用什么編程語(yǔ)言,你都可以找到庫(kù)來(lái)幫助你處理 JSON Schema。
- 版本控制:JSON Schema 本身也在不斷發(fā)展,目前有多個(gè)版本。每個(gè)版本添加了新的功能并對(duì)現(xiàn)有功能進(jìn)行了改進(jìn)。這使得 JSON Schema 可以適應(yīng)不斷變化的需求,同時(shí)保持向后兼容性。
通過(guò)使用 JSON Schema,開(kāi)發(fā)者可以創(chuàng)建更加健壯和可靠的應(yīng)用程序,確保數(shù)據(jù)的一致性和準(zhǔn)確性,同時(shí)提高開(kāi)發(fā)效率和降低維護(hù)成本。
2. 誕生背景
JSON Schema 的誕生背景源于對(duì) JSON 數(shù)據(jù)格式的廣泛采用及隨之而來(lái)的需要驗(yàn)證 JSON 數(shù)據(jù)結(jié)構(gòu)和內(nèi)容的需求。JSON(JavaScript Object Notation)是一種輕量級(jí)的數(shù)據(jù)交換格式,易于人閱讀和編寫(xiě),同時(shí)也易于機(jī)器解析和生成。隨著 Web 服務(wù)和應(yīng)用程序接口(API)的快速發(fā)展,JSON 成為了在網(wǎng)絡(luò)上進(jìn)行數(shù)據(jù)交換的一種流行方式。
在這種背景下,開(kāi)發(fā)者和系統(tǒng)架構(gòu)師面臨著如何有效驗(yàn)證 JSON 數(shù)據(jù)的挑戰(zhàn),特別是在復(fù)雜系統(tǒng)和跨團(tuán)隊(duì)合作中,確保數(shù)據(jù)的一致性和正確性變得尤為重要。以下是 JSON Schema 出現(xiàn)的幾個(gè)關(guān)鍵背景因素:
- 數(shù)據(jù)驗(yàn)證需求:隨著系統(tǒng)變得越來(lái)越依賴(lài)于動(dòng)態(tài)和靈活的數(shù)據(jù)交換,需要一種可靠的方法來(lái)驗(yàn)證數(shù)據(jù)結(jié)構(gòu)和內(nèi)容,以防止錯(cuò)誤數(shù)據(jù)導(dǎo)致的問(wèn)題。
- 自動(dòng)化和標(biāo)準(zhǔn)化:在自動(dòng)化處理過(guò)程中,如 API 的調(diào)用和響應(yīng),需要有一個(gè)標(biāo)準(zhǔn)方式來(lái)描述和驗(yàn)證數(shù)據(jù),從而減少人為干預(yù)和潛在的錯(cuò)誤。
- 跨語(yǔ)言和跨平臺(tái)交互:作為一種與語(yǔ)言無(wú)關(guān)的數(shù)據(jù)格式,JSON 被廣泛應(yīng)用于不同編程語(yǔ)言和平臺(tái)之間的交互。JSON Schema 提供了一種統(tǒng)一的方式來(lái)定義和驗(yàn)證數(shù)據(jù)結(jié)構(gòu),促進(jìn)了不同系統(tǒng)之間的互操作性。
- 文檔和協(xié)作:JSON Schema 還可以用作文檔,幫助開(kāi)發(fā)者理解數(shù)據(jù)模型的結(jié)構(gòu),促進(jìn)團(tuán)隊(duì)成員之間的溝通和協(xié)作。
因此,JSON Schema 應(yīng)運(yùn)而生,它不僅解決了數(shù)據(jù)驗(yàn)證的問(wèn)題,還支持文檔生成、自動(dòng)化測(cè)試和開(kāi)發(fā)工具集成等多種用途,成為了現(xiàn)代 Web 開(kāi)發(fā)中不可或缺的一個(gè)組成部分。
3. TS vs JSON Schema
JSON Schema 和 TypeScript(TS)都用于確保數(shù)據(jù)結(jié)構(gòu)的正確性,但它們?cè)趹?yīng)用和目的上存在一些關(guān)鍵區(qū)別:
- 應(yīng)用范圍:
- JSON Schema:主要用于描述和驗(yàn)證 JSON 數(shù)據(jù)結(jié)構(gòu),確保 JSON 數(shù)據(jù)符合預(yù)定義的格式。它是獨(dú)立于編程語(yǔ)言的,可以用于網(wǎng)絡(luò)傳輸中的數(shù)據(jù)驗(yàn)證、配置文件的驗(yàn)證等場(chǎng)景。
- TypeScript:是 JavaScript 的一個(gè)超集,它添加了靜態(tài)類(lèi)型定義的功能。TypeScript 主要用于在編譯時(shí)檢查代碼中的類(lèi)型錯(cuò)誤,提高開(kāi)發(fā)效率和代碼質(zhì)量。
- 執(zhí)行時(shí)機(jī):
- JSON Schema:通常在運(yùn)行時(shí)用于驗(yàn)證數(shù)據(jù),例如驗(yàn)證 API 請(qǐng)求/響應(yīng)的數(shù)據(jù)結(jié)構(gòu)。
- TypeScript:在編譯時(shí)進(jìn)行類(lèi)型檢查,編譯后的代碼轉(zhuǎn)換為普通的 JavaScript,運(yùn)行時(shí)不會(huì)進(jìn)行類(lèi)型檢查。
- 目的和使用場(chǎng)景:
- JSON Schema:用于確保數(shù)據(jù)遵守特定的格式和結(jié)構(gòu),常用于 API 數(shù)據(jù)交換和配置數(shù)據(jù)驗(yàn)證。
- TypeScript:旨在通過(guò)引入靜態(tài)類(lèi)型系統(tǒng)來(lái)提高代碼的可維護(hù)性和可讀性,主要用于開(kāi)發(fā)階段,幫助開(kāi)發(fā)者捕捉類(lèi)型相關(guān)的錯(cuò)誤。
- 語(yǔ)言和平臺(tái):
- JSON Schema:是一個(gè)獨(dú)立的規(guī)范,可以與任何支持 JSON 的編程語(yǔ)言一起使用。
- TypeScript:是一種編程語(yǔ)言,需要特定的編譯器(TypeScript 編譯器)將 TypeScript 代碼轉(zhuǎn)換為 JavaScript 代碼。
JSON Schema 主要關(guān)注于運(yùn)行時(shí)的數(shù)據(jù)驗(yàn)證,確保數(shù)據(jù)結(jié)構(gòu)的正確性;而 TypeScript 關(guān)注于編譯時(shí)的類(lèi)型檢查,提升開(kāi)發(fā)過(guò)程中的代碼質(zhì)量和安全性。兩者雖然在某些方面具有互補(bǔ)性,但服務(wù)于編程和數(shù)據(jù)處理的不同階段和方面。
4. 示例
4.1 最小示例
{ "$id": "https://example.com/person.schema.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Person", "type": "object", "properties": { "firstName": { "type": "string", "description": "The person's first name." }, "lastName": { "type": "string", "description": "The person's last name." }, "age": { "description": "Age in years which must be equal to or greater than zero.", "type": "integer", "minimum": 0 } }}
數(shù)據(jù):
{ "firstName": "John", "lastName": "Doe", "age": 21}
4.2 數(shù)組
{ "$id": "https://example.com/arrays.schema.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "A representation of a person, company, organization, or place", "type": "object", "properties": { "fruits": { "type": "array", "items": { "type": "string" } }, "vegetables": { "type": "array", "items": { "$ref": "#/$defs/veggie" } } }, "$defs": { "veggie": { "type": "object", "required": [ "veggieName", "veggieLike" ], "properties": { "veggieName": { "type": "string", "description": "The name of the vegetable." }, "veggieLike": { "type": "boolean", "description": "Do I like this vegetable?" } } } }}
數(shù)據(jù):
{ "fruits": [ "apple", "orange", "pear" ], "vegetables": [ { "veggieName": "potato", "veggieLike": true }, { "veggieName": "broccoli", "veggieLike": false } ]}
4.3 枚舉
{ "$id": "https://example.com/enumerated-values.schema.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Enumerated Values", "type": "object", "properties": { "data": { "enum": [42, true, "hello", null, [1, 2, 3]] } }}
數(shù)據(jù):
{ "data": [1, 2, 3]}
4.4 正則
{ "$id": "https://example.com/regex-pattern.schema.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Regular Expression Pattern", "type": "object", "properties": { "code": { "type": "string", "pattern": "^[A-Z]{3}-d{3}$" } }}
數(shù)據(jù):
{ "code": "ABC-123"}
4.5 嵌套
{ "$id": "https://example.com/complex-object.schema.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Complex Object", "type": "object", "properties": { "name": { "type": "string" }, "age": { "type": "integer", "minimum": 0 }, "address": { "type": "object", "properties": { "street": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string" }, "postalCode": { "type": "string", "pattern": "d{5}" } }, "required": ["street", "city", "state", "postalCode"] }, "hobbies": { "type": "array", "items": { "type": "string" } } }, "required": ["name", "age"]}
數(shù)據(jù):
{ "name": "John Doe", "age": 25, "address": { "street": "123 Main St", "city": "New York", "state": "NY", "postalCode": "10001" }, "hobbies": ["reading", "running"]}
4.6 條件驗(yàn)證
{ "$id": "https://example.com/conditional-validation-dependentRequired.schema.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Conditional Validation with dependentRequired", "type": "object", "properties": { "foo": { "type": "boolean" }, "bar": { "type": "string" } }, "dependentRequired": { "foo": ["bar"] }}
{ "$id": "https://example.com/conditional-validation-dependentSchemas.schema.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Conditional Validation with dependentSchemas", "type": "object", "properties": { "foo": { "type": "boolean" }, "propertiesCount": { "type": "integer", "minimum": 0 } }, "dependentSchemas": { "foo": { "required": ["propertiesCount"], "properties": { "propertiesCount": { "minimum": 7 } } } }}
{ "$id": "https://example.com/conditional-validation-if-else.schema.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Conditional Validation with If-Else", "type": "object", "properties": { "isMember": { "type": "boolean" }, "membershipNumber": { "type": "string" } }, "required": ["isMember"], "if": { "properties": { "isMember": { "const": true } } }, "then": { "properties": { "membershipNumber": { "type": "string", "minLength": 10, "maxLength": 10 } } }, "else": { "properties": { "membershipNumber": { "type": "string", "minLength": 15 } } }}
5. 驗(yàn)證器
JS 可使用 ajv:
// or ESM/TypeScript importimport Ajv from "ajv";// Node.js require:const Ajv = require("ajv");const ajv = new Ajv(); // options can be passed, e.g. {allErrors: true}const schema = { type: "object", properties: { foo: { type: "integer" }, bar: { type: "string" }, }, required: ["foo"], additionalProperties: false,};const data = { foo: 1, bar: "abc",};const validate = ajv.compile(schema);const valid = validate(data);if (!valid) console.log(validate.errors);
其他平臺(tái)可參考官網(wǎng):
來(lái)源-微信公眾號(hào):好朋友樂(lè)平
出處:https://mp.weixin.qq.com/s/G8RdfUpUjTYWtsFHdLIniw
版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn),該文觀點(diǎn)僅代表作者本人。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請(qǐng)發(fā)送郵件至 舉報(bào),一經(jīng)查實(shí),本站將立刻刪除。