4

この質問は言語に依存しません。フレームワークや実装について心配する必要はありません。すべてを実装できるとだけ言って、REST API を抽象的に見てみましょう。言い換えれば、私は現在フレームワークを構築していますが、この問題の解決策はどこにもありませんでした。

質問

コレクションを返す 2 つの独立した REST パスが交差する REST URL エンドポイントを構築するにはどうすればよいでしょうか? /users/1/comments簡単な例:とを交差させる方法は/companies/6/comments?

制約

すべてのエンドポイントは、単一のデータ モデル エンティティまたはエンティティのコレクションを返す必要があります。

これは非常に合理的な制約であり、ハイパーメディア API のすべての例は、draft-kelly-json-hal-07であってもこのようになります。

これが無効な制約であると思われる場合、またはより良い方法を知っている場合は、お知らせください。

と の 3 つのデータ型を持つアプリケーションがあるproductscategoriescompaniesます。各企業は、プロファイル ページにいくつかの製品を追加できます。製品を追加する際、製品にカテゴリを添付する必要があります。たとえば、この種のデータには次のようにアクセスできます。

  • GET /categoriesすべてのカテゴリのコレクションを返します
  • GET /categories/9ID 9 のカテゴリを返します
  • GET /categories/9/productsID 9 のカテゴリ内のすべての製品を返します
  • GET /companies/7/productsID 7 の会社のプロファイル ページに追加されたすべての製品を返します。

_linksハイパーメディアの部分は簡単なので、意図的に/省略_linksしまし/categories/companies

返される URL の書き方: 会社 (7) のすべての製品とカテゴリ (9) の製品は? 言い換えれば、どのように交差する/categories/9/products/companies/7/productsですか?

すべてのエンドポイントがデータ モデル リソースまたはそれらのコレクションを表す必要があると仮定すると、これは REST ハイパーメディア API の根本的な問題であると考えられます。 2 つの独立したグラフ パスの断面。

つまり、1 つのパスだけで 2 つの独立したパスを表すことはできないと思います。通常は のような 1 つのパスをトラバースしますA->B->CX->Y、 and があり、そこから来るZ->Yすべての が必要な場合、問題が発生します。YXZ

これまでのところ、私の提案はクエリ文字列を使用する/categories/9/products?intersect=/companies/9ことですが、もっとうまくやれるでしょうか?

なぜ私はこれが欲しいのですか?

SQL データベースの関係に基づいて REST ハイパーメディア API を自動生成するフレームワークを構築しているためです。URL からクエリへのトランス コンパイラと考えることができますSELECT ... JOIN ... WHEREが、API のクライアントは Hypermedia しか認識せず、クライアントは例のように交差を行う適切な方法を望んでいます。

4

4 に答える 4

3

REST を常にデータベース表現と見なすべきではないと思います。このケースは、私には特定の機能のようなものに見えます。私はこのようなもので行くと思います:

/intersection/comments?company=9&product=5

私はそれを書いた後、掘り下げてきましたが、これが私が見つけたものです( http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api ):

アクションを適切な RESTful 構造にマッピングする方法が本当にない場合があります。たとえば、複数リソースの検索を特定のリソースのエンドポイントに適用しても意味がありません。この場合、/search はリソースではありませんが、最も理にかなっています。これは問題ありません。API コンシューマの観点から正しいことを行い、混乱を避けるために明確に文書化されていることを確認してください。

于 2015-10-03T07:46:52.330 に答える
1

すべてのエンドポイントは、単一のデータ モデル エンティティまたはエンティティのコレクションを返す必要があります。

これは REST 制約ではありません。REST 制約について読みたい場合は、Fielding の論文を読んでください。

SQL データベースの関係に基づいて REST ハイパーメディア API を自動生成するフレームワークを構築しているためです。

これは間違ったアプローチであり、REST とは何の関係もありません。

REST では、応答でハイパーリンクを送信することにより、可能なリソース状態遷移 (または操作呼び出しテンプレート) を記述します。これらのハイパーリンクは、HTTP および URI 標準を使用して統一されたインターフェイスを構築する場合、HTTP メソッドと URI (および現在は関係のないその他のデータ) で構成されます (通常はそうします)。URI は (必ずしも) データベース エンティティおよびコレクション識別子ではありません。このような制約を適用すると、REST API ではなく CRUD API になります。

HTTP メソッドと既存のリソースの組み合わせで操作を記述できない場合は、新しいリソースが必要です。

あなたの場合、GET /users/1/commentsとのGET /companies/6/comments応答を集約したいので、GET と 3 番目のリソースを使用してリンクを定義する必要があります。

GET /comments/?users=1&companies=6
GET /intersection/users:1/companies:6/comments
GET /intersection/users/1/companies/6/comments

等...

于 2015-10-06T17:25:13.237 に答える
1

RESTful アーキテクチャとは、状態遷移を提供するハイパーメディア コントロールを含むリソースを返すことです。ここに表示されるのは、状態遷移の多段階プロセスです。ルート リソースがあり、何らかの/categories/9/products方法で利用可能なハイパーメディア コントロールを使用するとします。結果は hal で次のようになると思います。

{
  _links : {
     self : { href : "/categories/9/products"}
  },
  _embedded : {
     item : [
        {json of prod 1},
        {json of prod 2}
     ]
  }
}

クライアントがこれを別のコレクションと交差できるようにする場合は、これを実行するメカニズムをクライアントに提供する必要があります。ハイパーメディア コントロールを提供する必要があります。HAL には、リンク、テンプレート化されたリンク、およびコントロール タイプとしての埋め込みのみがあります。リンクで行きましょう..応答を次のように変更します。

{
  _links : {
     self : { href : "/categories/9/products"},
     x:intersect-with : [
          { 
            href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 1",
            title : "Company 6 products"
          },
          {
            href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 2",
            title : "Company 5 products"
          },
          {
            href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 3",
            title : "Company 7 products"
          }
     ]
  },
  _embedded : {
     item : [
        {json of prod 1},
        {json of prod 2}
     ]
  }
}

クライアントは、リンクのタイトル フィールドに基づいて適切なハイパーメディア コントロール (別名リンク) を選択するだけです。

それが最も簡単な解決策です。しかし、あなたはおそらく、私が何千ものリンクを望んでいない何千もの会社があると言うでしょう...もしそれが本当なら大丈夫です...私たちが持っている2つの中間で状態遷移を提供するだけです:

{
  _links : {
     self : { href : "/categories/9/products"},
     x:intersect-options : { href : "URL to a Paged collection of all intersect options"}, 
     x:intersect-with : [
          { 
            href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 1",
            title : "Company 6 products"
          },
          {
            href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 2",
            title : "Company 5 products"
          },
          {
            href : "URL IS ABSOLUTELY IRRELEVANT!!! but unique 3",
            title : "Company 7 products"
          }
     ]
  },
  _embedded : {
     item : [
        {json of prod 1},
        {json of prod 2}
     ]
  }
}

私がそこで何をしたか見てください。追加の状態遷移のための追加のコントロール。あなたがウェブページを持っているなら、あなたがするように。おそらくそれをポップアップに配置するでしょう。それは、アプリのクライアントがそのコントロールの結果でできることでもあります。

それは本当に簡単です...HTMLでそれを行う方法を考えて、同じことをしてください。

ここでの大きな利点は、クライアントが会社またはカテゴリ ID を知る必要がなく、テンプレートにプラグインする必要がないことです。ID は実装の詳細であり、クライアントはそれらが存在することを決して認識せず、ハイパーメディア コントロールを実行しただけです..これが RESTful です。

于 2015-10-17T04:08:16.303 に答える