100

RESTful API を介して公開する必要があるオブジェクト階層があり、URL をどのように構成し、何を返すべきかがわかりません。ベストプラクティスが見つかりませんでした。

動物から継承した犬と猫がいるとしましょう。犬と猫に対する CRUD 操作が必要です。動物全般の手術もできるようになりたいです。

私の最初のアイデアは、次のようなことをすることでした:

GET /animals        # get all animals
POST /animals       # create a dog or cat
GET /animals/123    # get animal 123

問題は、/animals コレクションが、まったく同じ構造 (犬と猫) を持たないオブジェクトを返したり取得したりできるため、「一貫性がない」ことです。異なる属性を持つオブジェクトを返すコレクションを持つことは「RESTful」と見なされますか?

別の解決策は、次のように、具象型ごとに URL を作成することです。

GET /dogs       # get all dogs
POST /dogs      # create a dog
GET /dogs/123   # get dog 123

GET /cats       # get all cats
POST /cats      # create a cat
GET /cats/123   # get cat 123

しかし今、犬と猫の関係は失われています。すべての動物を取得したい場合は、犬と猫の両方のリソースを照会する必要があります。動物のサブタイプが新しくなるたびに、URL の数も増えます。

別の提案は、これを追加して 2 番目のソリューションを拡張することでした。

GET /animals    # get common attributes of all animals

この場合、返される動物には、すべての動物に共通の属性のみが含まれ、犬固有の属性と猫固有の属性が削除されます。これにより、詳細は少なくなりますが、すべての動物を取得できます。返された各オブジェクトには、詳細で具体的なバージョンへのリンクが含まれている場合があります。

コメントや提案はありますか?

4

6 に答える 6

44

私は提案します:

  • リソースごとに1つのURIのみを使用する
  • 属性レベルでのみ動物を区別する

同じリソースに複数のURIを設定すると、混乱や予期しない副作用が発生する可能性があるため、決して良い考えではありません。そのため、単一のURIは。のような一般的なスキームに基づいている必要があります/animals

/animals「ベース」レベルで犬と猫のコレクション全体を処理するという次の課題は、 URIアプローチによってすでに解決されています。

犬や猫などの特殊なタイプを扱う最後の課題は、メディアタイプ内のクエリパラメータと識別属性の組み合わせを使用して簡単に解決できます。例えば:

GET /animalsAccept : application/vnd.vet-services.animals+json

{
   "animals":[
      {
         "link":"/animals/3424",
         "type":"dog",
         "name":"Rex"
      },
      {
         "link":"/animals/7829",
         "type":"cat",
         "name":"Mittens"
      }
   ]
}
  • GET /animals-すべての犬と猫を取得し、レックスとミトンの両方を返します
  • GET /animals?type=dog-すべての犬を取得し、レックスのみを返します
  • GET /animals?type=cat-すべての猫を取得します、ミトンだけになります

次に、動物を作成または変更する場合、関係する動物の種類を指定するのは発信者の責任です。

メディアタイプ:application/vnd.vet-services.animal+json

{
   "type":"dog",
   "name":"Fido"
}

上記のペイロードは、POSTまたはPUTリクエストで送信できます。

上記のスキームは、RESTを介したOO継承と同様の基本的な特性を備えており、大手術やURIスキームの変更なしに、さらに特殊化(つまり、より多くの動物タイプ)を追加する機能を備えています。

于 2012-06-04T15:13:40.877 に答える
8

この質問は、OpenAPI の最新バージョンで導入された最近の拡張機能のサポートにより、より適切に回答できます。

JSON スキーマ v1.0 以降、oneOf、allOf、anyOf などのキーワードを使用してスキーマを組み合わせ、検証されたメッセージ ペイロードを取得することが可能になりました。

https://spacetelescope.github.io/understanding-json-schema/reference/combining.html

ただし、OpenAPI (以前の Swagger) では、スキーマの構成がキーワードdiscriminator (v2.0+) およびoneOf (v3.0+) によって拡張され、ポリモーフィズムを真にサポートするようになりました。

https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaComposition

継承は、oneOf (サブタイプの 1 つを選択するため) と allOf (タイプとそのサブタイプの 1 つを結合するため) の組み合わせを使用してモデル化できます。以下は、POST メソッドのサンプル定義です。

paths:
  /animals:
    post:
      requestBody:
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/Dog'
              - $ref: '#/components/schemas/Cat'
              - $ref: '#/components/schemas/Fish'
            discriminator:
              propertyName: animal_type
     responses:
       '201':
         description: Created

components:
  schemas:
    Animal:
      type: object
      required:
        - animal_type
        - name
      properties:
        animal_type:
          type: string
        name:
          type: string
      discriminator:
        property_name: animal_type
    Dog:
      allOf:
        - $ref: "#/components/schemas/Animal"
        - type: object
          properties:
            playsFetch:
              type: string
    Cat:
      allOf:
        - $ref: "#/components/schemas/Animal"
        - type: object
          properties:
            likesToPurr:
              type: string
    Fish:
      allOf:
        - $ref: "#/components/schemas/Animal"
        - type: object
          properties:
            water-type:
              type: string
于 2018-01-07T00:15:00.493 に答える
4

/animals を指定すると、犬と魚の両方のリストが返されます。

<animals>
  <animal type="dog">
    <name>Fido</name>
    <fur-color>White</fur-color>
  </animal>
  <animal type="fish">
    <name>Wanda</name>
    <water-type>Salt</water-type>
  </animal>
</animals>

同様の JSON の例を実装するのは簡単です。

クライアントは、そこにある「name」要素 (共通属性) に常に依存できます。ただし、「type」属性によっては、動物表現の一部として他の要素が存在します。

このようなリストを返す際に、本質的に RESTful または unRESTful なものはありません。REST は、データを表現するための特定の形式を規定していません。それが言っているのは、データには何らかの表現が必要であり、その表現の形式はメディアタイプ (HTTP では Content-Type ヘッダー) によって識別されるということだけです。

ユースケースについて考えてみてください。混合動物のリストを表示する必要がありますか? それでは、混合動物データのリストを返します。犬のリストだけが必要ですか?まあ、そのようなリストを作ってください。

/animals?type=dog または /dogs のどちらを実行するかは、URL 形式を規定しない REST とは関係ありません。REST の範囲外の実装の詳細として残されています。REST は、リソースに識別子が必要であるとのみ述べています。形式は気にしないでください。

RESTful API に近づけるために、ハイパー メディア リンクを追加する必要があります。たとえば、動物の詳細への参照を追加します。

<animals>
  <animal type="dog" href="/animals/123">
    <name>Fido</name>
    <fur-color>White</fur-color>
  </animal>
  <animal type="fish" href="/animals/321">
    <name>Wanda</name>
    <water-type>Salt</water-type>
  </animal>
</animals>

ハイパー メディア リンクを追加することで、クライアント/サーバーの結合を減らすことができます。上記の場合、クライアントから URL 構築の負担を取り除き、サーバーに URL の構築方法を決定させます (定義上、それが唯一の権限です)。

于 2012-06-04T15:16:13.770 に答える
1

しかし、今では犬と猫の関係は失われています。

ただし、URIがオブジェクト間の関係を反映することは決してないことに注意してください。

于 2012-06-04T15:42:16.493 に答える