如何在OpenAPI 3.x中实现路径与查询参数的互斥枚举关联?
我有如下API路径:GET /pricing/{product-line}/countries/{country-code},其中product-line是枚举类型的路径参数,可选值为product-A、product-B。
需要为该请求添加名为includes的查询参数,该参数是数组类型,元素为字符串枚举值。product-A和product-B分别对应专属且互斥的枚举集合:
- 当
product-line=product-A时,includes的有效枚举值为A,B,C,D - 当
product-line=product-B时,includes的有效枚举值为F,G,H,I,J
请问在OpenAPI 3.x中如何实现这一需求?
我已尝试以下配置:
- name: includes in: query description: List of pricing components that are included in the response. style: form explode: false schema: anyOf: - $ref: '#/components/schemas/ListOfVerificationIncludes' - $ref: '#/components/schemas/ListOfVoiceIncludes'
对应的Schema定义如下:
ListOfVoiceIncludes: description: List of voice pricing components which will be used to retrieve pricing information for. type: array uniqueItems: true minItems: 1 items: $ref: "#/components/schemas/VoiceIncludes"
VoiceIncludes: description: Pricing component which will be used to retrieve pricing information for. type: string enum: - pstn - did - inapp - sip - features
我还考虑过把includes拆分为两个查询参数voice-includes和verification-includes,但不确定如何实现路径参数与查询参数的互斥性(即product-A对应verification-includes,product-B对应voice-includes)。
方案一:用OpenAPI 3.1的if/then/else做条件约束(推荐)
OpenAPI 3.1支持通过if/then/else定义参数间的依赖关系,能直接把路径参数product-line和查询参数includes的校验逻辑绑定起来,完美匹配你的需求。
完整配置示例:
paths: /pricing/{product-line}/countries/{country-code}: get: parameters: - name: product-line in: path required: true schema: type: string enum: [product-A, product-B] - name: includes in: query description: List of pricing components to include in the response style: form explode: false required: true schema: type: array uniqueItems: true minItems: 1 items: type: string # 根据product-line的值限制includes的枚举范围 if: parameters: product-line: enum: [product-A] then: parameters: includes: schema: items: enum: [A, B, C, D] else: parameters: includes: schema: items: enum: [F, G, H, I, J]
这个配置的效果:
- 当
product-line为product-A时,includes的元素只能是A/B/C/D中的值 - 当
product-line为product-B时,includes的元素只能是F/G/H/I/J中的值 - 保持查询参数名称统一为
includes,符合你最初的设计
方案二:拆分查询参数并添加互斥校验
如果坚持要拆分为voice-includes和verification-includes,可以用oneOf定义参数组合的互斥规则:
paths: /pricing/{product-line}/countries/{country-code}: get: parameters: - name: product-line in: path required: true schema: type: string enum: [product-A, product-B] - name: verification-includes in: query description: 仅当product-line为product-A时可用的组件列表 style: form explode: false schema: type: array uniqueItems: true minItems: 1 items: enum: [A, B, C, D] - name: voice-includes in: query description: 仅当product-line为product-B时可用的组件列表 style: form explode: false schema: type: array uniqueItems: true minItems: 1 items: enum: [F, G, H, I, J] # 定义互斥的参数组合规则 oneOf: - description: product-A对应的参数组合 parameters: product-line: enum: [product-A] verification-includes: required: true voice-includes: required: false - description: product-B对应的参数组合 parameters: product-line: enum: [product-B] voice-includes: required: true verification-includes: required: false
注意:这种方式需要你的OpenAPI工具支持oneOf对参数组合的校验,部分工具兼容性可能稍差。
对你原有尝试的补充说明
你之前用anyOf定义includes的Schema,虽然能覆盖两种枚举集合,但无法关联路径参数product-line的值——用户可能在product-line=product-A时传入product-B的枚举值,这种错误无法被校验拦截。而方案一的if/then/else刚好解决了这个问题,把路径参数和查询参数的校验逻辑强绑定了。
内容的提问来源于stack exchange,提问作者C. Vasile

