如何在OpenAPI 3.1规范中复现Swagger里allOf的继承行为?
问题背景
Swagger文档曾给出示例展示OpenAPI模型继承的实现方式,原示例代码如下:
components: schemas: BasicErrorModel: type: object required: - message - code properties: message: type: string code: type: integer minimum: 100 maximum: 600 ExtendedErrorModel: allOf: # Combines the BasicErrorModel and the inline model - $ref: "#/components/schemas/BasicErrorModel" - type: object required: - rootCause properties: rootCause: type: string
在OpenAPI 3.0规范中,该示例可正常工作,ExtendedErrorModel会包含基础对象和派生对象的全部属性:
但切换到OpenAPI 3.1规范(使用"next"网页编辑器)后,示例失效,工具会将allOf中的各个成员视为独立内容,$ref仅显示为文本:
核心问题:这是OpenAPI 3.1规范语义变更导致的预期行为吗?若是,该继承机制有何替代方案?
解答
1. 是否为规范变更导致的预期行为?
这不是OpenAPI 3.1规范语义变更的预期行为,而是部分工具(如Swagger Editor的next版本)对OpenAPI 3.1的$ref和allOf处理逻辑存在兼容性问题。
OpenAPI 3.1完全兼容3.0中allOf结合$ref实现模型继承的方式——因为3.1基于JSON Schema Draft 2020-12,而allOf在JSON Schema中依然是用于合并多个Schema的关键字,$ref的引用逻辑也未发生根本性变化。问题出在工具对3.1规范的解析渲染上,而非规范本身的语义变更。
2. 替代方案
如果遇到工具兼容问题,可采用以下两种替代方式实现模型继承:
方案一:$ref与扩展属性共存
利用JSON Schema Draft 2020-12允许$ref所在对象包含其他关键字的特性,将基础模型引用与扩展属性直接写在同一个对象中:
components: schemas: BasicErrorModel: type: object required: - message - code properties: message: type: string code: type: integer minimum: 100 maximum: 600 ExtendedErrorModel: $ref: "#/components/schemas/BasicErrorModel" type: object required: - rootCause properties: rootCause: type: string
方案二:使用$dynamicRef(适用于复杂继承场景)
如果需要更灵活的多态或继承逻辑,可以使用OpenAPI 3.1支持的$dynamicRef关键字实现动态引用与Schema扩展:
components: schemas: BasicErrorModel: type: object required: - message - code properties: message: type: string code: type: integer minimum: 100 maximum: 600 ExtendedErrorModel: $dynamicRef: "#/components/schemas/BasicErrorModel" type: object required: - rootCause properties: rootCause: type: string
另外,也可以等待工具(如Swagger Editor next)完成对OpenAPI 3.1规范的完整兼容修复,之后原有的allOf写法即可正常使用。
内容的提问来源于stack exchange,提问作者Maciej Stachowski

