OpenAPI / Swagger 模型继承在 AWS API Gateway 中的应用

9
我正在尝试使用AWS API Gateway实现Swagger或OpenAPI 3.0中定义的API。
在此API中,一个端点接受一个抽象基础模型(我们称之为Pet以保持与广为流传的Swagger示例的一致性),但实际上需要从Pet派生的具体模型,例如Dog
可以通过Pet上的type属性确定具体模型。
具体模型可以添加其他字段。
当然,这是一个discriminator的工作:
definitions:
    Pet:
        discriminator: petType
        required:
        - name
        - petType # required for inheritance to work
        properties:
        name: 
            type: string
        petType:
            type: string
    Cat:
        allOf:
        - $ref: '#/definitions/Pet' # Cat has all properties of a Pet
        - properties: # extra properties only for cats
            huntingSkill:
                type: string
                default: lazy
                enum:
                - lazy
                - aggressive
    Dog:
        allOf:
        - $ref: '#/definitions/Pet' # Dog has all properties of a Pet
        - properties: # extra properties only for dogs
            packSize:
                description: The size of the pack the dog is from
                type: integer

(来源:这里)

然而,AWS API Gateway 不支持discriminator参考)。

好吧,这很令人烦恼,但也许我们可以通过使用 OpenAPI 3.0 在模式中利用oneOf来定义API:

paths:
    /pets:
        patch:
            requestBody:
                content:
                    application/json:
                        schema:
                            oneOf:
                                - $ref: '#/components/schemas/Cat'
                                - $ref: '#/components/schemas/Dog'

然而(再次强调),AWS API Gateway也不支持oneOf参考文献)。

有没有人知道如何在 AWS API Gateway 中实现这种模型架构,特别是利用继承模式(Pet <- Dog)的 body 验证优势?或者有没有一种方法可以避免为每个具体类型都编写方法的解决方法?


1
这个问题有解决方案了吗? - Tolga Evcimen
2
@TolgaEvcimen - 据我所知没有。我们已经停止使用AWS API网关,因为存在过多的不一致性和问题。 - KevinD
2个回答

5
我想添加另一种解决问题的方式,更好的方式! 关键问题在于之前的尝试中我使用了OpenAPI 3.0.0,然而3.0.1似乎不再与oneOf指令有任何问题。
以下是工作示例:
{
  "openapi": "3.0.1",
  "info": {
    // (...)
  },
  "paths": {
    "/pets": {
      "post": {
        "summary": "Post a pet",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PetRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            // (...)
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Cat": {
        "type": "object",
        "required": [
          "cat_stuff"
        ],
        "properties": {
          "cat_stuff": {
            "type": "string"
          }
        }
      },
      "Dog": {
        "type": "object",
        "required": [
          "dog_stuff"
        ],
        "properties": {
          "dog_stuff": {
            "type": "string"
          },
        }
      },
      "PetRequest": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/Cat"
          },
          {
            "$ref": "#/components/schemas/Dog"
          }
        ]
      }
    },
    // Many fields omitted (...)
}

使用与这些模式不匹配的负载进行卷曲会导致以下错误,这证明了oneOf的工作效果!
(...)
"error_messages": [
    "[instance failed to match exactly one schema (matched 0 out of 2)]"
],

请您亲自测试并留下反馈意见。

1
基本上,解决方案是:不要在 content: application/json: schema: 下直接使用 oneOf,而是将响应作为模型进行包装(在 components 部分创建一个模型),并在您的模型中使用 oneOf。这样就可以了!现在 API 网关导出的 yaml 将显示正确的 oneOf。 - Shawn

2
这可能不是对您问题的完全满意的答案,但有一种方法可以在API Gateway中使用oneOf您可以根据AWS的要求为各个模型使用JSON schema

由于这个事实,您可以在API Gateway部署后更新您的模型。
# Reformatted here for readability
VALUE='"{\"$schema\": \"http://json-schema.org/draft-04/schema#\",
         \"title\": \"A Pet Request\",
         \"oneOf\":
        [{ \"$ref\": \"https://apigateway.amazonaws.com/restapis/xxxxxxx/models/Cat\" },
         { \"$ref\": \"https://apigateway.amazonaws.com/restapis/xxxxxxx/models/Dog\" }]}"'


aws apigateway update-model \
--rest-api-id xxxxxxx \
--model-name 'PetRequest' \
--patch-operations "op=replace,path=/schema,value=${VALUE}"

这个解决方案可以工作,但可能不是非常可持续的,因为您需要在每次部署后执行patch-operations
如果我找到更好的方法,我可能会更新这个答案。

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