理解 OpenAPI 中的 oneOf(避免困惑)
Source: Dev.to
Introduction
在使用 OpenAPI 设计 API 时,oneOf 常常显得令人生畏。它功能强大,但容易被误用——尤其是在 PATCH 接口中。下面我们用简单的方式把它拆解说明。
What oneOf Means in OpenAPI (JSON Schema)
- 请求体 必须完全匹配 列表中的 一个 schema。
- 不能为零。
- 必须恰好一个。
Example
schema:
oneOf:
- $ref: '#/components/schemas/InverterPatch'
- $ref: '#/components/schemas/EVPatch'
- $ref: '#/components/schemas/EVCSPatch'
这告诉 OpenAPI:“负载必须符合上述 恰好一个 schema。”
oneOf Is Tricky with PATCH
PATCH 请求是部分更新。客户端通常只发送少量字段。
想象下面的负载:
{
"reverseFlow": true
}
如果 reverseFlow 同时出现在 InverterPatch 和 EVCSPatch 中,负载就会匹配 多个 schema。
🚫 结果: 验证失败,因为 oneOf 要求恰好匹配一个。
Using a Discriminator to Resolve Ambiguity
discriminator:
propertyName: type
此时客户端发送:
{
"type": "inverter",
"reverseFlow": true
}
OpenAPI 能立即知道:
type = inverter→ 使用InverterPatch→ 验证成功。
💡 discriminator 告诉 OpenAPI 应该使用哪个 schema 进行验证。
When to Use oneOf (with a Discriminator)
- 你有多个 schema。
- 某些字段会重叠。
- 客户端可能发送部分更新。
- 你希望在 OpenAPI 层面进行验证,而不是仅靠后端逻辑。
When to Avoid oneOf
- 你不需要 OpenAPI 在 schema 之间做选择。
- 后端已经知道资源类型。
- 你可以在运行时对特定类型的规则进行验证。
在这些情况下,使用一个包含可选字段的单一 PATCH schema 更简单,也往往更合适。
Summary
oneOf= 必须恰好匹配一个 schema。- 字段重叠 +
PATCH= 歧义。 - discriminator 能消除这种歧义。
- 除非真的需要在 schema 之间进行选择,否则不要使用
oneOf。
正确使用 oneOf 能让你的 API 更安全、更具自我文档化;使用不当,则会让 PATCH 接口变得痛苦。