如何用JSON Schema实现查询仅允许另一Schema定义的键并支持多值匹配?
实现复用枚举键+支持多值查询的JSON Schema方案
这是个很常见的JSON Schema复用需求,我来给你拆解实现步骤,既避免代码重复,又满足查询时的多值匹配要求:
第一步:构建可复用的options.json
我们先把带枚举值的键定义在这个Schema里,并且把枚举值抽离到可复用的块中,方便后续query schema引用:
// options.json (基于Draft 07,兼容性更广) { "$schema": "http://json-schema.org/draft-07/schema#", // 抽离枚举定义到definitions,方便后续复用 "definitions": { "colorEnum": { "type": "string", "enum": ["red", "green", "blue"] }, "sizeEnum": { "type": "string", "enum": ["small", "medium", "large"] } }, "type": "object", "properties": { "color": {"$ref": "#/definitions/colorEnum"}, "size": {"$ref": "#/definitions/sizeEnum"} }, // 禁止额外未定义的键 "additionalProperties": false }
第二步:构建query.json实现键复用+多值支持
接下来,我们要让query schema仅允许使用options.json里的键,同时每个键的值可以是单个枚举值或者多个枚举值的数组(满足多值匹配需求):
// query.json { "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", // 复用options里定义的所有键,但重写每个键的验证规则 "properties": { "color": { "anyOf": [ // 允许单个枚举值(直接引用options里的定义) {"$ref": "options.json#/definitions/colorEnum"}, // 允许枚举值的数组,且数组元素不重复、至少有一个值 { "type": "array", "items": {"$ref": "options.json#/definitions/colorEnum"}, "uniqueItems": true, "minItems": 1 } ] }, "size": { "anyOf": [ {"$ref": "options.json#/definitions/sizeEnum"}, { "type": "array", "items": {"$ref": "options.json#/definitions/sizeEnum"}, "uniqueItems": true, "minItems": 1 } ] } }, // 严格禁止使用options里未定义的键 "additionalProperties": false, // 可选:要求至少传一个查询参数 "minProperties": 1 }
核心逻辑解释
- 复用枚举定义:通过
$ref直接引用options.json里的枚举,避免重复编写枚举值,后续修改枚举只需要改options.json即可。 - 多值支持:用
anyOf让每个键的值可以是单个枚举值,或者由枚举值组成的数组;uniqueItems: true防止数组里出现重复值(可根据需求移除)。 - 键合法性限制:
additionalProperties: false确保查询请求只能使用options.json里定义的键,杜绝非法参数。
验证示例
合法的查询请求
{ "color": ["red", "green"], "size": "medium" }
非法的查询请求
- 使用未定义的键:
{ "shape": "circle" // shape不在options的键列表中,验证失败 }
- 使用不在枚举中的值:
{ "color": "yellow" // yellow不在colorEnum的枚举里,验证失败 }
- 数组包含重复值:
{ "color": ["red", "red"] // uniqueItems限制重复,验证失败 }
进阶优化(Draft 2020-12版本)
如果你的JSON Schema支持Draft 2020-12,可以用$dynamicRef更优雅地复用整个键结构,不需要手动复制properties:
// options.json (Draft 2020-12) { "$schema": "https://json-schema.org/draft/2020-12/schema", "$anchor": "optionsSchema", "$defs": { "colorEnum": {"type": "string", "enum": ["red", "green", "blue"]}, "sizeEnum": {"type": "string", "enum": ["small", "medium", "large"]} }, "type": "object", "properties": { "color": {"$ref": "#/$defs/colorEnum"}, "size": {"$ref": "#/$defs/sizeEnum"} }, "additionalProperties": false }
// query.json (Draft 2020-12) { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", // 动态复用options的键结构 "$dynamicRef": "options.json#optionsSchema", "$dynamicAnchor": "optionsSchema", // 重写每个键的验证规则以支持多值 "properties": { "color": { "anyOf": [ {"$ref": "options.json#/$defs/colorEnum"}, {"type": "array", "items": {"$ref": "options.json#/$defs/colorEnum"}, "uniqueItems": true} ] }, "size": { "anyOf": [ {"$ref": "options.json#/$defs/sizeEnum"}, {"type": "array", "items": {"$ref": "options.json#/$defs/sizeEnum"}, "uniqueItems": true} ] } }, "additionalProperties": false }
这种方式更适合键较多的场景,不需要手动维护query schema里的properties列表,直接复用options的键结构。
内容的提问来源于stack exchange,提问作者Ruben
相关产品推荐
相关产品推荐

