Подтвердить что ты не робот

Наследование и композиция

В моем "упрощенном" 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)

Я попытался определить эту связь в swagger со следующим 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, а затем создадут классы дочерних ответов, которые состоят из соответствующих классов заголовка/тела (показаны в исходном коде внизу). Тем не менее, я уверен, что либо это неправильный способ сделать что-то, либо что моя реализация неверна. Я не смог найти пример наследования в спецификации swagger 2.0 (показано ниже), но нашел пример composition.

enter image description here

Я вполне уверен, что этот "дискриминатор" играет большую роль, но не уверен, что мне нужно делать.

Вопрос

Может ли кто-нибудь показать мне, как предполагается реализовать композицию + наследование в swagger 2.0 (JSON), предпочтительно путем "исправления" моего примера кода ниже. Было бы замечательно, если бы я мог указать класс ErrorResponse, который наследует от ответа, где атрибут "result" в заголовке всегда задан как "ошибка".

{
    "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 могут быть расширены и вставлены в любой объект ответа, который выполняется в случае filename_response, который использует дочернее имя filename_response_body базового класса response_body. И ошибки, и успешные ответы используют объект "ответ".

enter image description here

4b9b3361

Ответ 1

Как новичок в swagger, я не могу найти официальную документацию о полиморфизме и композиции, которую легко раскрыть, потому что в ней отсутствует пример, Когда я искал сеть, есть много хороших примеров, ссылающихся на swagger 1.2, когда extends был действительным.

Для swagger 2.0 Я нашел хороший пример в источниках спецификаций swagger на github через google group

Основываясь на приведенных выше источниках, вот короткий пример действительного наследования в 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

Ответ 2

Я обнаружил, что композиция прекрасно работает даже без определения discriminator.

Например, 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

Отображается как:

Визуализация ответа

И мы можем расширить его, чтобы уточнить настраиваемую схему поля result:

  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

И он будет правильно отображаться как:

FooServiceResponse визуализация

Обратите внимание, что для этого достаточно allOf, и не используется поле discriminator. Это хорошо, потому что это работает, и это важно, как я думаю, инструменты смогут генерировать код без поля discriminator.

Ответ 3

Все ответы здесь превосходны уже, но я просто хочу добавить небольшую заметку о композиции против наследования. В соответствии с Swagger/OpenAPI Spec для реализации композиции, с использованием свойства allOf достаточно, поскольку @oblalex правильно указывает. Однако для реализации наследования вам нужно использовать allOf с discriminator, как в примере by @TomaszSętkowski.

Кроме того, я нашел еще несколько примеров Swagger как состав, и inheritance в Handican API. Они являются частью отличной учебной серии Swagger/OpenAPI от Арно Лоурета, которую я думаю, что каждый должен проверить.

Ответ 4

В стандартном примере Swagger 2.0, который вы поделили, изображено отношение композиции, в частности, оно фиксирует "является своего рода" отношением типа супер-типа/подтипа ", но оно само по себе не является полиморфизмом.

Было бы, если бы вы могли ссылаться на базовое определение Pet в качестве входного параметра, а затем выбрать Cat или ввести объект Cat JSON в качестве значения для запроса ввода и сделать это приемлемым для пользовательского интерфейса Swagger.

Я не мог заставить это работать напрямую.

Лучшее, что я мог получить, это установить для параметра extraProperties значение true для базового объекта (например, Pet), указать Pet с использованием ссылки на указатель JSON в качестве входной схемы и, наконец, скопировать и вставить объект ценности Cat JSON в интерфейс Swagger. Так как дополнительные свойства разрешены, пользовательский интерфейс Swagger генерирует действительную полезную нагрузку запроса ввода.