JSON Schemaには,oneOfという便利な構文が用意されている。これは,与えられたスキーマのうちどれか1つだけがvalidなときvalidとする構文だ。
さて,そのoneOfの挙動で困ったのでメモする。具体的には,オブジェクト型Aと,別のオブジェクト型B,そしてAとBとをallOfでマージしたABとがあるとき,AとBとABとのoneOfを構成することができないのだ。
例として以下にスキーマを示す。このスキーマ自体はvalidだが,実は#abを許容できない。
{ "definitions": { "a": { "$id": "#a", "additionalProperties": true, "type": "object", "required": ["a"], "properties": { "a": { "type": "number" } } }, "b": { "$id": "#b", "additionalProperties": true, "type": "object", "required": ["b"], "properties": { "b": { "type": "number" } } }, "ab": { "$id": "#ab", "additionalProperties": false, "properties": { "a": {}, "b": {} }, "allOf": [{ "$ref": "#a" }, { "$ref": "#b" }] } }, "$schema": "http://json-schema.org/draft-07/schema#", "oneOf": [{ "$ref": "#a" }, { "$ref": "#b" }, { "$ref": "#ab" }] }
oneOfの挙動
どうして#abを許容しないかというと,oneOfの挙動にもとづいている。oneOfは,「与えられたスキーマでJSONをvalidateしていき,どれか1つのスキーマにだけvalidなときにvalidになる」構文だ。この例では,#aか#bか#abのうち,いずれか1つだけがvalidにならなければならない。
しかしながら,#abに対してvalidなJSONは#aにも#bにもvalidになってしまう(allOfで制約を満たしているのだから当然だが)ので,いずれか1つだけのスキーマにvalidになることができない。
大抵の場合,本当に欲しいのはoneOfではなく,「どれかにマッチする(anyOf)」なので,そう置換する。