Swaggerの継承と構成


82

私の「簡略化された」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を使用して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クラスを作成してさまざまな応答を作成し、次に関連するヘッダー/ bodyクラスで構成される子応答クラスを作成しようとします(下部のソースコードに示されています)。ただし、これが間違った方法であるか、私の実装が正しくないことは確かです。swagger 2.0仕様(以下に表示)で継承の例を見つけることができませんでしたが、構成の例を見つけました。

ここに画像の説明を入力してください

この「弁別器」が大きな役割を果たすことは確かですが、私が何をする必要があるのか​​はわかりません。

質問

誰かがswagger2.0(JSON)でcomposition + inheritanceを実装する方法を教えてもらえますか?できれば以下のサンプルコードを「修正」してください。また、ヘッダーの「result」属性が常に「error」に設定されている応答から継承する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」オブジェクトのインスタンス化であることを示すことを目的としています。response_headerオブジェクトとresponse_bodyオブジェクトは、拡張して任意の応答オブジェクトに挿入できます。これは、基本response_bodyクラスのfilename_response_body子を使用するfilename_responseの場合に実行されます。エラー応答と成功応答はどちらも「応答」オブジェクトを使用します。

ここに画像の説明を入力してください


1
作曲のサンプルあります、共有する価値がないほどひどいです。私はあなたのスペックがどのように見えるべきかについて作業します。UIは現在それをサポートしていませんが、2.0の完全なサポートが利用可能になるとサポートすることに注意してください。
ロン

1
そして、私が飛び込む前に、もう1つ、構成または継承を探していますか?作曲は基本的に言っていI have the properties of X and my own properties.ます。継承は関係を示唆しX is my parent. I have its properties and my own.ます。継承は、使用されている親の特定のモデルのセットが適用可能であると言いたい場合に役立ちます。
ロン

1
この例では、継承構成の両方の使用法を一度に示すことを望んでいました。明らかに、どちらかを単独で簡単に使用できることはわかっていますが、この場合、すべての応答は基本の「応答」クラスの子です。また、応答クラスは、ヘッダーと本文の2つのオブジェクトで「構成」されています。
プログラマー

2
はっきりしていなかったかもしれません。継承は構成の拡張です。相続があれば、構成があります。構成があれば、必ずしも継承はありません。また、サンプルでは、​​「応答」モデルはどこにも使用されていません。私はそれを無視して、それがどのように見えるべきかを示すべきですか?
ロン

ああ、継承と構成の関係に気づいていませんでした。したがって、継承を使用して両方を表示します。使用されていない応答モデルに関しては、要求が応答するfilename_response子の「extends」とともに使用する必要があります。
プログラム

回答:


114

闊歩で初心者として、私は見つけられません公式ドキュメント、それはので、簡単undestandにpolimorphismと組成についての例を欠い。ネットを検索したところ、有効なときにswagger1.2を参照した良い例がたくさんありextendsます。

ため闊歩2.0私に良い例を見つけたgithubの上闊歩スペック源これを介してGoogleのグループ

上記のソースに基づいて、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

本当にありがとう!これは私にとってはうまくいきます。にeditor.swagger.io、小さなバグがあります。モデルセクションに、Petモデルが複数回表示されます。これらのモデルの内容は問題ありません。名前だけが間違っています。
schellingerht 2017

@schellingerhteditor2.swagger.ioこの問題は発生しません
Shiplu Mokaddim 2017

継承を定義するこの方法で私が見つけた唯一の問題は、petTypeプロパティが生成されたクラスでは少し役に立たないということです。空になります。しかし、少なくとも私が思ったようにクラス階層を生成します。ありがとう!
xarlymg89 2018

上記のように継承jsonを作成するには、親クラスと子クラスに次のように注釈を付ける必要があります。@ ApiModel(discriminator = "type"、subTypes = {Cat.class、Dog.class})public abstract class Animal {} @ ApiModel(parent = Animal.class)public calss Cat extends Animal {}
Janet

識別子は、インターフェイスを実装する場合にのみPet使用されますか?クラスAがクラスBを拡張する場合はどうでしょうか?それも使用する必要がありますか?ありがとう
Bionix14 4120年

23

の定義がなくても、構成は正常に機能することがわかりました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フィールドなしでコードを生成できるようになります。


私も使用allOfしましたが、どういうわけかopenapi.yaml、サブクラスにスーパークラスのプロパティが冗長に含まれていることがわかりました。それは正しいですか?
Bionix14 4120年

9

ここでのすべての答えはすでに優れていますが、構成と継承についてのマイナーなメモを追加したいと思います。Swagger / OpenAPI仕様によると、コンポジションを実装allOfするには、@ oblalexが正しく指摘しているように、プロパティを使用するだけで十分です。ただし、継承を実装するにallOfdiscriminator@TomaszSętkowskiの例のように、を使用する必要があります。

また、API Handymanで、構成継承の両方のSwaggerの例をさらにいくつか見つけました。これらは、ArnaudLauretによる優れたSwagger / OpenAPIチュートリアルシリーズの一部であり、誰もがチェックする必要があると思います。


1
@関連するリンクを投稿することは良いスタートですが、実際に役立つ答えになるためには、リンクにある関連するテキストも引用する必要があります。リンクは頻繁に停止するため、リンクのみの回答はお勧めしません。
Stijn de Witt 2017

3

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

Petの基本定義を入力パラメーターとして参照し、Catを選択するか、入力リクエストの値としてCat JSONオブジェクトを入力し、これをSwaggerUIに受け入れられるようにするとよいでしょう。

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

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


特定のハックに緊密に結合して機能させたい場合を除いて、ネットワーク上でポリモーフィズムを実行する(またはデータエンティティを公開する)ことはできません。
user1496062 2016年

ポリモーフィズムは継承によって有効になりますが、継承を使用する必要はありません。論理的には、継承は「is-a」関係であり、コンポジションは「has-a」関係です。実装言語とドメインのユースケースによっては、2つの間の境界線がぼやけることがあります。しかし、それが出発点です。Fwiw、ディスクリミネーターはポリモーフィックタイプの逆シリアル化を可能にします。他のアプローチがあります(たとえば、Javaクラス名を含む)。しかし、同意しましたが、これらは扱いにくく、持ち運びできない可能性があります。たとえば、PythonクライアントはJavaクラス名で何をしますか?
チャーリーライツェル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.