为什么在Swagger/OpenAPI 2.0中使用`additionalProperties`来表示字典/映射?

51
尽管我已经看过OpenAPI规范中的示例:

type: object
additionalProperties:
  $ref: '#/definitions/ComplexModel'
我不明白为什么对于Map/Dictionary来说使用additionalProperties是正确的模式。

规范中唯一具体提到additionalProperties的内容也没有什么帮助:

以下属性取自JSON Schema定义,但它们的定义已调整为Swagger规范。 它们的定义与JSON Schema相同, 仅在原始定义引用JSON Schema定义的地方,改为使用Schema Object定义。

  • items
  • allOf
  • properties
  • additionalProperties
2个回答

52

陈,我认为你的答案是正确的。

以下是一些可能有用的背景信息:

在JavaScript中,JSON最初的上下文环境,对象类似于字符串到值的哈希映射,其中一些值是数据,其他值是函数。您可以将每个名称-值对视为属性。但是JavaScript没有类,因此属性名称未预定义,每个对象都可以拥有自己独立的属性集。

JSON Schema使用properties关键字来验证预先知道的名称-值对;并使用additionalProperties(或patternProperties,不支持OpenAPI 2.0)来验证未知的属性。

为了清晰起见:

  • 映射中的属性名称或“键”必须是字符串。它们不能是数字或任何其他值。
  • 正如您所说,属性名称应该是唯一的。不幸的是,JSON规范并不严格要求唯一性,但唯一性是建议的,并且大多数JSON实现都期望如此。更多背景在这里
  • propertiesadditionalProperties可以单独或组合使用。当仅使用additionalProperties而没有properties时,对象基本上作为map<string,T>运行,其中T是additionalProperties子模式中描述的类型。也许这有助于回答您最初的问题。
  • 在针对单个模式评估对象时,如果属性名称与properties中指定的名称之一匹配,则其值只需要有效地与为该属性提供的子模式相匹配。如果提供了additionalProperties子模式,则仅用于验证未包含在properties映射中的属性。
  • Swagger核心Java库中实现的additionalProperties存在一些限制。我在这里记录了这些限制。

2
Epstien,虽然您的回答是正确的,但我不确定它是否解决了我一直在苦苦思考的问题:为什么additionalProperty映射(双关语未必有意)到字典或映射。此外,如果我的答案大多正确,则有些不正确,并且我没有从您的答案中理解到其中的错误之处。 - Chen Levy
陈先生,感谢您的评论。我更新了我的答案,并增加了更多的细节,希望对您和其他读者有所帮助。我的回答重点是提供一些进一步的背景和见解,而不是纠正您的答案。希望我的第三个要点,在上下文中看来,能够回答您最初的问题(虽然不一定比您自己的答案更好)。 - Ted Epstein
1
陈,你的回答里只有几个点可能不是100%正确的,我在我的回答中试图解决这些问题。(1)你的回答中说“键(它们的名称或数字)”,似乎表明属性可以使用数字值作为键。实际上,名称必须是字符串。(2)你说“additionalProperties将匹配任何属性名称”,可能很显然,但我想指出的是它不会匹配包含在“properties”关键字下的属性名称。 - Ted Epstein
Ted,谢谢你的评论。当我写“their names or number”时,我是指“键的名称或键的数量”,我已经修改了我的回答以避免混淆。 - Chen Levy

49

首先,我找到了一个关于additionalProperties的更好解释:

对于一个对象,如果赋予了这个属性,在除了在properties中定义的属性之外所有其他属性名都是允许的。它们的值必须都匹配此处给出的模式对象。如果没有赋予这个属性,则只允许在properties中定义的属性。

所以这就是我最终理解它的方式:

使用properties, 我们可以定义一组已知的属性,类似于Python的namedtuple,然而如果我们希望有类似于Python的字典,或者任何其他散列表/映射,我们无法事先规定有多少键以及它们是什么,那么我们应该使用additionalProperties

additionalProperties将匹配任何属性名称(作为字典的键),$reftype将成为字典值的架构,由于对于每个给定对象不应该有多个相同名称的属性,我们将获得唯一键的强制执行。

请注意,与Python的dict接受任何不可变值作为键不同,因为这里的键本质上是属性名,它们必须是字符串。(感谢Ted Epstein提供的澄清)。这种限制可以追溯到在json规范中的pair:= string : value


1
很棒的解释 - 希望我早点发现它! - danday74

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接