如何验证扁平化JSON键?基于JSON Schema的REST查询校验问询
验证扁平化JSON查询键的通用方案
核心问题拆解
你需要验证REST查询中扁平化键(如emp_meta.manages)是否符合给定JSON Schema的结构,难点在于处理oneOf分支(比如emp_meta对应两种员工类型,仅Manager有manages字段),以及关联字段的合法性校验。
方案一:预编译Schema的合法路径映射
先把Schema中所有可能的合法扁平化路径提取出来,同时记录每个路径对应的前置条件,后续直接用这个映射校验查询键。
实现步骤
- 递归遍历Schema收集路径:处理
$ref和oneOf分支,把所有嵌套字段展开为扁平化路径,同时记录路径生效的条件(比如emp_meta.manages仅在emp_category=MANAGER时合法)。 - 路径与条件关联:针对
oneOf分支中的枚举关联(比如emp_category的枚举值对应emp_meta的不同类型),把这类关联作为路径的前置条件存入映射。
伪代码示例
def collect_valid_paths(schema, current_path="", conditions=None): valid_paths = {} conditions = conditions or [] # 处理引用类型 if "$ref" in schema: ref_parts = schema["$ref"].lstrip("#/").split("/") ref_schema = schema for part in ref_parts: ref_schema = ref_schema[part] return collect_valid_paths(ref_schema, current_path, conditions.copy()) # 处理oneOf分支 if "oneOf" in schema: for sub_schema in schema["oneOf"]: # 处理枚举分支(如emp_category的可选值) if "enum" in sub_schema: enum_vals = sub_schema["enum"] new_conds = conditions + [(current_path, enum_vals)] continue # 处理对象分支(如emp_meta的两种员工类型) sub_paths = collect_valid_paths(sub_schema, current_path, conditions.copy()) for path, conds in sub_paths.items(): if path not in valid_paths: valid_paths[path] = [] valid_paths[path].extend(conds) return valid_paths # 处理对象类型的属性 if schema.get("type") == "object" and "properties" in schema: for prop, prop_schema in schema["properties"].items(): new_path = f"{current_path}.{prop}" if current_path else prop sub_paths = collect_valid_paths(prop_schema, new_path, conditions.copy()) for path, conds in sub_paths.items(): if path not in valid_paths: valid_paths[path] = [] valid_paths[path].extend(conds) return valid_paths # 非对象类型,返回当前路径 return {current_path: conditions} # 生成合法路径映射 employee_schema = {...} # 你的Employee Schema valid_path_map = collect_valid_paths(employee_schema)
查询校验逻辑
拿到查询中的扁平化键后:
- 检查键是否存在于
valid_path_map中,不存在则直接返回非法。 - 检查该键对应的前置条件是否在查询中满足。比如查询里有
emp_meta.manages,则必须同时存在emp_category=MANAGER的条件,否则判定为非法。
方案二:改用结构化查询语法
如果扁平化键的校验逻辑过于复杂,可以直接让查询载荷的结构与Schema对齐,避免扁平化解析的麻烦。
示例结构化查询
{ "employee": { "AND": [ {"emp_category": "MANAGER"}, {"emp_meta": {"department": "R&D"}}, {"emp_meta": {"manages": "John*"}} ] } }
校验优势
- 直接复用原Schema的验证逻辑:针对每个查询条件,生成对应的Schema片段进行校验(比如用Manager类型的Schema校验
{"emp_meta": {"manages": "John*"}})。 - 无需处理扁平化键的解析,条件关联逻辑更直观(比如
emp_meta的结构自动对应emp_category指定的类型)。
关于必填字段的澄清
Schema中的必填字段是针对数据对象的约束,而非查询条件。查询中可以使用任何合法存在的字段(无论是否必填),不需要强制包含必填字段。比如你可以只查询emp_meta.department,无需同时指定emp_meta.id。
内容的提问来源于stack exchange,提问作者V1666
相关产品推荐
相关产品推荐

