大摇大摆的继承与创作

在我的“简化”API 中,所有的响应都是从一个基本的“响应”类派生出来的(继承)。响应类是由元数据填充的头的 镇定,以及包含用户请求的核心数据的主体。响应(在 JSON 中)的布局使得所有元数据都在第一个“层”上,而主体是一个单独的属性,本身称为“主体”

response
|--metadata attribute 1 (string/int/object)
|--metadata attribute 2 (string/int/object)
|--body (object)
|--body attribute 1 (string/int/object)
|--body attribute 2 (string/int/object)

我试图用以下 JSON 大张旗鼓地定义这种关系:

{
...
"definitions": {
"response": {
"allOf": [
{
"$ref": "#/definitions/response_header"
},
{
"properties": {
"body": {
"description": "The body of the response (not metadata)",
"schema": {
"$ref": "#/definitions/response_body"
}
}
}
}
]
},
"response_header": {
"type": "object",
"required": [
"result"
],
"properties": {
"result": {
"type": "string",
"description": "value of 'success', for a successful response, or 'error' if there is an error",
"enum": [
"error",
"success"
]
},
"message": {
"type": "string",
"description": "A suitable error message if something went wrong."
}
}
},
"response_body": {
"type": "object"
}
}
}

然后,我尝试通过创建从 body/header 继承的各种 body/header 类来创建不同的响应,然后创建由相关 header/body 类组成的子响应类(见底部的源代码)。但是,我可以肯定,要么这是一种错误的做事方式,要么我的实现是不正确的。我无法在 斯瓦格2.0规范中找到继承的例子(如下所示) ,但是找到了 作文的一个例子。

enter image description here

我非常确定这个“辨别器”有很大的作用,但不确定我需要做什么。

提问

有没有人能告诉我如何在 swagger 2.0(JSON)中实现组合 + 继承,最好是通过“修复”下面的示例代码。如果我可以指定一个从响应继承的 ErrorResponse 类,其中头部的“ result”属性总是设置为“ error”,那将是非常好的。

{
"swagger": "2.0",
"info": {
"title": "Test API",
"description": "Request data from the system.",
"version": "1.0.0"
},
"host": "xxx.xxx.com",
"schemes": [
"https"
],
"basePath": "/",
"produces": [
"application/json"
],
"paths": {
"/request_filename": {
"post": {
"summary": "Request Filename",
"description": "Generates an appropriate filename for a given data request.",
"responses": {
"200": {
"description": "A JSON response with the generated filename",
"schema": {
"$ref": "#/definitions/filename_response"
}
}
}
}
}
},
"definitions": {
"response": {
"allOf": [
{
"$ref": "#/definitions/response_header"
},
{
"properties": {
"body": {
"description": "The body of the response (not metadata)",
"schema": {
"$ref": "#/definitions/response_body"
}
}
}
}
]
},
"response_header": {
"type": "object",
"required": [
"result"
],
"properties": {
"result": {
"type": "string",
"description": "value of 'success', for a successful response, or 'error' if there is an error",
"enum": [
"error",
"success"
]
},
"message": {
"type": "string",
"description": "A suitable error message if something went wrong."
}
}
},
"response_body": {
"type": "object"
},
"filename_response": {
"extends": "response",
"allOf": [
{
"$ref": "#definitions/response_header"
},
{
"properties": {
"body": {
"schema": {
"$ref": "#definitions/filename_response_body"
}
}
}
}
]
},
"filename_response_body": {
"extends": "#/definitions/response_body",
"properties": {
"filename": {
"type": "string",
"description": "The automatically generated filename"
}
}
}
}
}

图表更新

为了弄清楚我想要的是什么,我已经创建了下面这个非常基本的图,目的是展示所有的响应都是由(组合)使用 response _ header 和 response _ body 对象的任意组合构建的“响应”对象的实例化。Response _ header 和 response _ body 对象可以扩展并插入到任何响应对象中,这在使用基 response _ body 类的 filename _ response _ body 子对象的情况下完成。错误和成功的响应都使用“ response”对象。

enter image description here

102271 次浏览

As a beginner in swagger I don't find the official documentation about polimorphism and composition easy to undestand, because it lacks an example. When I searched the net, there are lots of good examples refering to swagger 1.2 when extends was valid.

For swagger 2.0 I found a good example in swagger spec sources on github via this google group

Based on above sources, here is a short valid inheritance example in YAML:

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

The Swagger 2.0 standard example you have shared depicts a composition relationship, specifically it captures an "is a kind of" super-type/sub-type relationship however it is not polymorphism in and of itself.

It would be if you could reference the base definition of Pet as an input parameter, then pick Cat or enter a Cat JSON object as the value for the input request, and have this acceptable to Swagger UI.

I could not get this to directly work.

The best I could get working was to set additionalProperties to true on the base object (e.g. Pet), specify Pet using JSON pointer reference as the input schema, and finally copy and paste my Cat JSON value object into Swagger UI. Since the additional properties are allowed Swagger UI generated a valid input request payload.

I've found that composition works fine even without definition of discriminator.

For example, base Response:

definitions:
Response:
description: Default API response
properties:
status:
description: Response status `success` or `error`
type: string
enum: ["success", "error"]
error_details:
description: Exception message if called
type: ["string", "object", "null"]
error_message:
description: Human readable error message
type: ["string", "null"]
result:
description: Result body
type: ["object", "null"]
timestamp:
description: UTC timestamp in ISO 8601 format
type: string
required:
- status
- timestamp
- error_details
- error_message
- result

Is rendered as:

Response visualization

And we can extend it to refine custom schema of result field:

  FooServiceResponse:
description: Response for Foo service
allOf:
- $ref: '#/definitions/Response'
- properties:
result:
type: object
properties:
foo_field:
type: integer
format: int32
bar_field:
type: string
required:
- result

And it will be correctly rendered as:

FooServiceResponse visualization

Note, that allOf is enough for this to work and no discriminator field is used. This is good, because it works and this is important, as I think, tools will be able to generate code without discriminator field.

All the answers here are excellent already, but I just want to add a minor note about composition versus inheritance. According to the Swagger/OpenAPI Spec, to implement composition, using the allOf property is enough, as @oblalex correctly points out. However, to implement inheritance, you need to use allOf with discriminator, as in the example by @TomaszSętkowski.

Also, I found some more Swagger examples of both composition and inheritance at API Handyman. They're part of an excellent Swagger/OpenAPI tutorial series by Arnaud Lauret that I think everyone should check out.