web-dev-qa-db-ja.com

Swaggerの継承と構成

私の「簡素化された」APIでは、すべての応答は基本の「応答」クラスから派生します(inherit)。応答クラスは、composedメタデータで満たされたヘッダーと、ユーザーが要求しているコアデータを含む本文です。応答(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を使用して、この関係をswaggerで定義しようとしました。

{
    ...
    "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クラスで構成される子応答クラスを作成しようとします(下部のソースコードを参照)。ただし、これが物事を行うための間違った方法であるか、私の実装が間違っているかのどちらかです。 swagger 2.0 specification (以下に示す)で継承の例を見つけることができませんでしたが、 composition の例を見つけました。

enter image description here

この「差別者」が果たすべき役割は大きいと確信していますが、何をする必要があるのか​​はわかりません。

質問

以下のサンプルコードを「修正」することにより、誰かがSwagger 2.0(JSON)で合成+継承を実装する方法を教えてください。また、ヘッダーの「結果」属性が常に「エラー」に設定されている応答から継承するErrorResponseクラスを指定できると便利です。

{
    "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を使用するfilename_responseの場合に実行されます。エラーと成功の両方の応答は、「応答」オブジェクトを使用します。

enter image description here

71
Programster

Swaggerの初心者として、私は 公式ドキュメント ポリモーフィズムと構成について理解しやすいとは思いません。なぜなら、には例がないからです。ネットを検索したとき、多くの 良い例extendsが有効であるときにswagger 1.2を参照していました。

swagger 2.0の場合、 githubのswagger spec sources を介して 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
100

discriminatorを定義しなくても構図がうまく機能することがわかりました。

たとえば、ベース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

次のようにレンダリングされます。

Response visualization

そして、それを拡張して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 visualization

これが機能するにはallOfで十分であり、discriminatorフィールドは使用されないことに注意してください。これは機能するため、これは重要です。これは、ツールがdiscriminatorフィールドなしでコードを生成できるようになるためです。

20
oblalex

ここでのすべての答えはすでに優れていますが、 composition vs inheritance に関するちょっとしたメモを追加したいだけです。 Swagger/OpenAPI Spec によると、compositionを実装するには、allOfプロパティを使用するだけで十分です- @ oblalexが正しく指摘している 。ただし、inheritanceを実装するには、 @の例のように、allOfとともにdiscriminatorを使用する必要があります。 TomaszSętkowski

また、API Handymanで compositioninheritance の両方のSwaggerの例をいくつか見つけました。これらはArnaud Lauretによる excellent Swagger/OpenAPIチュートリアルシリーズ の一部であり、誰もがチェックすべきだと思います。

8
DynamicDispatch

共有したSwagger 2.0の標準例は、構成関係を示しています。具体的には、「一種」のスーパータイプ/サブタイプの関係をキャプチャしますが、それ自体はポリモーフィズムではありません。

入力パラメーターとしてPetの基本定義を参照し、Catを選択するか、入力要求の値としてCat JSONオブジェクトを入力し、これをSwagger UIで受け入れられるようにすることができます。

これを直接動作させることはできませんでした。

基本的なオブジェクト(Petなど)でadditionalPropertiesをtrueに設定し、JSONポインター参照を入力スキーマとして使用してPetを指定し、最後にCat JSON値オブジェクトをSwagger UIにコピーして貼り付けることができました。追加のプロパティが許可されているため、Swagger UIは有効な入力要求ペイロードを生成しました。

3
user6317389