JSON Schema を使えば,自分が欲しい構造の JSON データであるかを簡単に判定できるので,とても便利です.
まずは JavaScript で JSON Schema を使ってみます.
ajv を使う
JSON schema バリデータの実装はたくさんありますが,今回は,Ajv JSON schema validator を使って,以下のようなスクリプトを実行してみます.
package.json
{ "dependencies": { "ajv": "^8.12.0" } }
main.mjs
import Ajv from "ajv"; const ajv = new Ajv(); // draft-07 const schema = { type: "object", properties: { a: { type: "integer" }, b: { type: "string" }, }, required: ["a"], additionalProperties: false, } const data = { a: 1, b: 2, } const validate = ajv.compile(schema); const valid = validate(data); console.log(valid);
schema
をコンパイルして data
を検証するわけです.これを実行すると,b
プロパティが string ではなく integer になっているので,false
と出力されます.
const data = { a: 1, b: "Banana", // fix }
これで true
を出力されます.
JSON schema を作成
JSON Schema - Creating your first schema
上記の記事にまとまっています.要約すると type
, properties
をそれっぽく指定していくだけです.
JSON の構造を JSON で記述できるので面白いです.
JSON Schema を検証
任意の JSON Schema を検証できる JSON Schema があれば便利だと思って調べたところ,Meta-schema という名前で用意されていました.
"draft-2020-12" を使用して "draft-07" の Mata-schema をコンパイルし,先ほどの JSON Schema を検証してみましょう.なお,本当は "draft-07" を使用して "draft-07" をコンパイルしたかったのですが,ajv に重複する Meta-schema を登録できなかったので,諦めました.
main.mjs
import Ajv2020 from "ajv/dist/2020.js"; const ajv = new Ajv2020({ strict: false }); const schema = { "$schema": "http://json-schema.org/draft-07/schema#", "$id": "http://json-schema.org/draft-07/schema#", "title": "Core schema meta-schema", "definitions": { "schemaArray": { "type": "array", "minItems": 1, "items": { "$ref": "#" } }, "nonNegativeInteger": { "type": "integer", "minimum": 0 }, "nonNegativeIntegerDefault0": { "allOf": [{ "$ref": "#/definitions/nonNegativeInteger" }, { "default": 0 }] }, "simpleTypes": { "enum": ["array", "boolean", "integer", "null", "number", "object", "string"] }, "stringArray": { "type": "array", "items": { "type": "string" }, "uniqueItems": true, "default": [] } }, "type": ["object", "boolean"], "properties": { "$id": { "type": "string", "format": "uri-reference" }, "$schema": { "type": "string", "format": "uri" }, "$ref": { "type": "string", "format": "uri-reference" }, "$comment": { "type": "string" }, "title": { "type": "string" }, "description": { "type": "string" }, "default": true, "readOnly": { "type": "boolean", "default": false }, "examples": { "type": "array", "items": true }, "multipleOf": { "type": "number", "exclusiveMinimum": 0 }, "maximum": { "type": "number" }, "exclusiveMaximum": { "type": "number" }, "minimum": { "type": "number" }, "exclusiveMinimum": { "type": "number" }, "maxLength": { "$ref": "#/definitions/nonNegativeInteger" }, "minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, "pattern": { "type": "string", "format": "regex" }, "additionalItems": { "$ref": "#" }, "items": { "anyOf": [{ "$ref": "#" }, { "$ref": "#/definitions/schemaArray" }], "default": true }, "maxItems": { "$ref": "#/definitions/nonNegativeInteger" }, "minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, "uniqueItems": { "type": "boolean", "default": false }, "contains": { "$ref": "#" }, "maxProperties": { "$ref": "#/definitions/nonNegativeInteger" }, "minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, "required": { "$ref": "#/definitions/stringArray" }, "additionalProperties": { "$ref": "#" }, "definitions": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "properties": { "type": "object", "additionalProperties": { "$ref": "#" }, "default": {} }, "patternProperties": { "type": "object", "additionalProperties": { "$ref": "#" }, "propertyNames": { "format": "regex" }, "default": {} }, "dependencies": { "type": "object", "additionalProperties": { "anyOf": [{ "$ref": "#" }, { "$ref": "#/definitions/stringArray" }] } }, "propertyNames": { "$ref": "#" }, "const": true, "enum": { "type": "array", "items": true, "minItems": 1, "uniqueItems": true }, "type": { "anyOf": [ { "$ref": "#/definitions/simpleTypes" }, { "type": "array", "items": { "$ref": "#/definitions/simpleTypes" }, "minItems": 1, "uniqueItems": true } ] }, "format": { "type": "string" }, "contentMediaType": { "type": "string" }, "contentEncoding": { "type": "string" }, "if": { "$ref": "#" }, "then": { "$ref": "#" }, "else": { "$ref": "#" }, "allOf": { "$ref": "#/definitions/schemaArray" }, "anyOf": { "$ref": "#/definitions/schemaArray" }, "oneOf": { "$ref": "#/definitions/schemaArray" }, "not": { "$ref": "#" } }, "default": true } const data = { type: "object", properties: { a: { type: "integer" }, b: { type: "string" }, }, required: ["a"], additionalProperties: false, } const validate = ajv.compile(schema); const valid = validate(data); console.log(valid);
true
と出力されました.Meta-schema は自分自身と全ての JSON Schema を検証可能な JSON Schema であり,JSON Schema は任意の JSON を検証できるので,全ての JSON は検証可能になっているというわけです.
日常で使う Meta-schema
ajv に用意されている,ajv.validateSchema(schema: object): boolean
を使用します.この関数は schema が追加された時に自動で呼び出されるので,ajv.compile(schema)
を実行したら,meta-schema による検証が行われるようになっています*1.したがって,以下の2行だけを記載すれば十分です.
const validate = ajv.compile(schema); const valid = validate(data);