使用 AWS API Gateway 继承 OpenAPI / Swagger 模型

Kev*_*inD 5 amazon-web-services swagger aws-api-gateway openapi

我正在尝试使用 AWS API Gateway 实现在 Swagger 或 OpenAPI 3.0 中定义的 API。

这个 API 中的一个端点采用一个抽象的基本模型(让我们称它为Pet与陈旧的 Swagger 示例一致),但实际上需要一个从Pet……Dog例如派生的具体模型。

具体模型可以由 上的type属性确定Pet

具体模型可以添加其他字段。

当然,这是一份工作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
Run Code Online (Sandbox Code Playgroud)

(取自这里

但是,AWS API Gateway 不支持discriminator( ref )。

好吧,烦人,但也许一种解决方法是使用 OpenAPI 3.0 定义 API,并oneOf在架构中使用:

paths:
    /pets:
        patch:
            requestBody:
                content:
                    application/json:
                        schema:
                            oneOf:
                                - $ref: '#/components/schemas/Cat'
                                - $ref: '#/components/schemas/Dog'
Run Code Online (Sandbox Code Playgroud)

但是(再次),AWS API Gateway 不支持oneOfref)。

有谁知道如何使用 AWS API Gateway 实现这种性质的模型架构,尤其是利用继承模式 ( Pet <- Dog)的主体验证?或者确实是一种解决方法,而不必为每种具体类型提供方法?

小智 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 (...)
}
Run Code Online (Sandbox Code Playgroud)

使用与这些模式之一不匹配的有效负载进行卷曲会产生以下错误,这证明它oneOf正在按预期工作!

(...)
"error_messages": [
    "[instance failed to match exactly one schema (matched 0 out of 2)]"
],
Run Code Online (Sandbox Code Playgroud)

请自行测试并留下一些反馈。


小智 2

这可能不能完全令人满意地回答您的问题,但有一种oneOf与 API Gateway 一起使用的方法。您可以根据 AWS 对各个模型使用 JSON 架构

因此,您可以在部署 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}"
Run Code Online (Sandbox Code Playgroud)

该解决方案有效,但可能不太可持续,因为您需要patch-operations在每次部署后执行。

如果我找到更好的方法,我可能会更新这个答案。