如何使用Swagger指定属性可以为null或引用

47

如何在swagger中指定属性为空或引用?讨论了如何使用Jsonschema来指定属性为空或引用。

我正在寻找在swagger中实现相同的功能。

为了概括上述答案,在jsonschema中,可以像这样做:

{
   "definitions": {
      "Foo": {
         # some complex object
      }
   },

   "type": "object",
   "properties": {
      "foo": {
         "oneOf": [
            {"$ref": "#/definitions/Foo"},
            {"type": "null"}
         ]
      }
   }
}

回答中的关键点是使用了oneOf

我问题的关键点:

  1. 我有一个复杂的对象,想要保持DRY,所以将其放在定义部分以便在整个swagger规范中重复使用:其他属性的值;响应对象等等。

  2. 在我的规范中,某些属性可以是对这种对象的引用,也可以是null。

在Swagger中如何指定这一点,因为Swagger不支持oneOfanyOf

注意:一些Swagger实现使用x-nullable(或类似的东西)来指定属性值可以为null,但是,$ref会用它引用的内容替换对象,因此任何使用x-nullable的地方都会被忽略。

4个回答

74

OpenAPI 3.1

将属性定义为$reftype: 'null'anyOf

YAML版本:

foo:
  anyOf:
    - type: 'null'   # Note the quotes around 'null'
    - $ref: '#/components/schemas/Foo'

JSON版本:

"foo": {
    "anyOf": [
        { "type": "null" },
        { "$ref": "#/components/schemas/Foo" }
    ]
}

为什么使用anyOf而不是oneOf?如果引用的模式本身允许空值,则oneOf将验证失败,而anyOf将起作用。

OpenAPI 3.0

YAML版本:

foo:
  nullable: true
  allOf:
  - $ref: '#/components/schemas/Foo'

JSON版本:

"foo": {
    "nullable": true,
    "allOf": [
        { "$ref": "#/components/schemas/Foo" }
    ]
}

在OAS 3.0中,需要将$ref包装到allOf中,以便将$ref与其他关键字组合起来,因为$ref会覆盖任何同级关键字。这在OpenAPI规范存储库中进一步讨论:引用对象与“nullable”不良组合

我正在使用.NET Core上的Swashbuckle 5x,并且想要在"payload": { "$ref": "#/components/schemas/MyClass" }中添加"nullable": true,使其变为"payload": { "nullable": true, "$ref": "#/components/schemas/MyClass" }。有人知道如何使用Swashbuckle选项来实现这个吗? - Adam Diament
1
@AdamDiament 请提出新问题 - Helen
谢谢Helen,我已经在这里完成了(https://dev59.com/WVIG5IYBdhLWcg3w3l4l) - Adam Diament
这种类型的表达式在我使用的库(python connexion/flask/OpenAPI 3.0)中支持很差。引用的类代码会被生成两次,并且当我提交无效数据时,错误消息也会混乱。这令人失望。 - Kiruahxh
为什么使用 anyOf 而不是 oneOf?如果引用的模式本身允许 null,则 oneOf 将无法通过验证,而 anyOf 可以工作。如果 null 是引用模式的一部分,那么这样做是否有意义? - Ben Longo
显示剩余2条评论

8
对于某些原因,在使用OpenAPI 3.0时,使用nullable: true后跟allOf没有起效果。为了解决这个问题,我最终定义了一个名为null_type必须为空引用,可以在anyOf结构中使用。如下所示:
allOf:
  - anyOf:
      - $ref: "#/components/schemas/null_type"
      - $ref: "#/components/schemas/your_ref"
  - description: "optionally add other properties here..."

其中:

schemas:
  null_type:
    title: "OpenAPI 3.0 null-type ref"
    description: "for adding nullability to a ref"
    enum: [null]

  your_ref:
    ...

这是唯一一个让我使用的所有工具都满意的解决方案。 - jpbochi
我也确认了这一点(使用Postman OpenAPI 3.0.0 API定义)。 - boylec1986
1
如果您在规范中使用YAML,枚举应该是一个YAML数组(而不是JSON数组):schemas: null_type: title: "OpenAPI 3.0 null-type ref" description: "用于向引用添加可为空性" enum: - null - Axel GeNuS
1
如果您正在使用YAML进行规范,枚举应该是一个YAML数组(而不是JSON数组):schemas: null_type: title: "OpenAPI 3.0 null-type ref" description: "用于向引用添加可为空性" enum: - null - undefined
@AxelGeNuS JSON是YAML的一个子集,JSON数组有什么问题吗? - undefined

5
很难做到,甚至几乎不可能。您有以下选择:

等待

这个问题有一个非常长的讨论 链接,或许有一天会解决...

使用供应商扩展

您可以使用供应商扩展x-oneOfx-anyOf。我已经走过这条艰难的路:您必须升级所有使用的'swagger工具'以考虑这些供应商扩展。

在我的情况下,我们只需要:

  • 开发自己的Jax-RS解析器,并使用自定义注释从源代码中提取swagger API文件
  • 扩展swagger-codegen以考虑这些扩展,以为我们的客户端生成Java代码
  • 开发我们自己的swagger-ui:为了简化这项工作,我们添加了一个预处理步骤,将我们的带有扩展的swagger模式转换为有效的json模式。在javascript中,表示json模式比swagger模式容易找到模块。相反,我们放弃了使用“尝试”按钮测试API的想法。

这是一年前的事了,也许现在...

重构您的API

许多项目不需要anyOf和oneOf,为什么我们不这样做呢?


2
“等等” - 是的,显然v3版本将支持oneOf、anyOf,但我们还需要等待能够消费它的工具和库。 - djpinne
"扩展" - 我在使用 Python (带有 bravado-core) 消费我的 Swagger,但它没有你提到的扩展...糟糕。 - djpinne
“重构” - 这需要简化我的 API 以适应规范...我需要规范来适应我的 API!现在,我能想到的另一件事情是对于返回 $ref-or-null 的情况 现在返回该属性,这在客户端(我的情况下是 JavaScript)会将“未定义”视为“null”。但我讨厌这个想法。 - djpinne

0
我在使用.net6的webAPI中遇到了类似的问题,使用Swashbuckle时也出现了类似的问题。我有一个属性是一个对象,但也可以为空。当对象为空时,它无法进行反序列化。
例如,下面的代码可以正常工作并进行反序列化。
{
  "Foo":"bar"
  "Details" {
    "Test":"value",
    "Test2":"value"
  }
}

但是无法反序列化
{
  "Foo":"bar"
  "Details": null
}

为了解决这个问题,我在我的Swagger设置中添加了以下内容。
builder.Services.AddSwaggerGen(options =>
{
     options.UseAllOfToExtendReferenceSchemas();
});

生成了以下内容
"someObject": {
  "allOf": [
    {
      "$ref": "#/components/schemas/SomeObject"
    }
  ],
  "nullable": true
},

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