REST API-APIはネストされたJSONオブジェクトを返す必要がありますか?


37

JSON APIに関しては、応答をフラット化し、ネストされたJSONオブジェクトを避けるのが良いでしょうか?

例として、IMDbに似ているがビデオゲーム用のAPIがあるとします。いくつかのエンティティ、Game、Platform、ESRBRating、GamesとPlatformsをマップするGamePlatformMapがあります。

ID 1のゲームを取得する/ game / 1をリクエストすると、プラットフォームとesrbRatingがネストされたゲームオブジェクトを返します。

{
  "id": 1,
  "title": "Game A",
  "publisher": "Publisher ABC",
  "developer": "Developer DEF",
  "releaseDate": "2015-01-01",
  "platforms": [
    {"id":1,"name":"Xbox"},
    {"id":2,"name":"Playstation"}
  ],
  "esrbRating": {
    "id": 1,
    "code": "E",
    "name": "Everyone"
  }
}

JPA / Hibernateのようなものを使用している場合、FETCH.EAGERに設定されていれば自動的にこれを行うことがあります。

もう1つのオプションは、単にAPIを追加して、エンドポイントを追加することです。

その場合、/ game / 1が要求されると、ゲームオブジェクトのみが返されます。

{
  "id": 1,
  "title": "Game A",
  "publisher": "Publisher ABC",
  "developer": "Developer DEF",
  "releaseDate": "2015-01-01",
}

プラットフォームやESRBRatingが必要な場合は、次を呼び出す必要があります。

/ game / 1 / platform / game / 1 / esrb

このメソッドは、クライアントが必要とするデータと必要なタイミングに応じて、サーバーにさらにいくつかの呼び出しを追加する可能性があるようです。

最後に、このようなものが返されると思いました。

{
  "id": 1,
  "title": "Game A",
  "publisher": "Publisher ABC",
  "developer": "Developer DEF",
  "releaseDate": "2015-01-01",
  "platforms": ["Xbox","Playstation"]
}

ただし、これは、IDやその他の情報がプラットフォームオブジェクトに関連付けられている必要がないことを前提としています。

一般に、APIから返されたJSONオブジェクトを構造化する最良の方法は何かを尋ねます。エンティティにできるだけ近づけるようにする必要がありますか、またはドメインオブジェクトまたはデータ転送オブジェクトを使用しても問題ありませんか?メソッドには、データアクセス層でのより多くの作業またはクライアントでのより多くの作業のいずれかのトレードオフがあることを理解しています。

また、APIのバックエンドテクノロジーとしてSpring MVCを使用し、永続化のためにJPA / HibernateまたはMyBatisのいずれかを使用することに関連した回答も聞きたいです。


6
埋め込まれたオブジェクトを返すという異議がある場合、それはありますか?さまざまなエンドポイントから埋め込みオブジェクトを個別に返すことは、非常に面倒です(遅いことは言うまでもありません)。
ロバートハーベイ

1
個人的に私はそれに異議はありません。ベストプラクティスと見なされるものを私は知らないだけです。同僚は、AngularJSの埋め込みオブジェクトを操作するのは簡単ではないと主張しており、AngularJSアプリのEmberがAPIを消費することを最終的に望んでいます。AngularやEmberについては、それが影響を与えるかどうかを知るのに十分な知識がありません。
greyfox

3
答えは、ドメインオブジェクト、DTO、ViewModelオブジェクト、KitchenSinkオブジェクトのどれを返すかによって異なります。どのオブジェクトを返すかは、アプリケーションで必要なものと、インターネット上でのオブジェクトの動作によって決まります。 例: Webページを請求書のデータで埋めようとしている場合、必要なものすべてを含むオブジェクトを返す可能性が非常に高くなります(広告申込情報でAJAXを使用する場合など)。
ロバートハーベイ

これは、ゲームをリクエストするときに、ジャンル、プラットフォーム、ESRBRatingを知りたいと思うケースです。それは理にかなっている。Javaの観点からの設計の観点から、JPAエンティティを持つエンティティパッケージ、そしてビジネスオブジェクト/ DTOであるドメインパッケージをユーザーに返すことをお勧めしますか?
greyfox

1
サーバーへの呼び出しは高価です。複数の呼び出しを使用してデータを送信する必要があるAPIは、1回の呼び出しですべてを取得できるAPIよりも遅くなります(多くの場合、後者が不要な情報を返す場合でも)。
ロボット

回答:


11

別の選択肢(HATEOASを使用)。これは簡単で、ほとんどの場合、HATEOASの使用に応じてリンクタグをjsonに追加します。

http://api.example.com/games/1

{
  "id": 1,
  "title": "Game A",
  "publisher": "Publisher ABC",
  "developer": "Developer DEF",
  "releaseDate": "2015-01-01",
  "platforms": [
    {"_self": "http://api.example.com/games/1/platforms/53", "name": "Playstation"},
    {"_self": "http://api.example.com/games/1/platforms/34", "name": "Xbox"},
  ]
}

http://api.example.com/games/1/platforms/34

{
  "id": 34,
  "title": "Xbox",
  "publisher": "Microsoft",
  "releaseDate": "2015-01-01",
  "testReport": "http://api.example.com/games/1/platforms/34/reports/84848.pdf",
  "forms": [
    {"type": "edit", "fields: [] },
  ]
}

もちろん、すべてのデータをすべてのリストに埋め込むこともできますが、データが多すぎる可能性があります。この方法で、必要なデータを埋め込み、それを本当に使いたい場合はさらに読み込むことができます。

技術的な実装にはキャッシュを含めることができます。プラットフォームAPIをまったくロードせずに、プラットフォームのリンクと名前をゲームオブジェクトにキャッシュし、即座に送信できます。その後、必要に応じてロードできます。

たとえば、フォーム情報を追加したことがわかります。詳細なjsonオブジェクトには、ゲームのリストにロードするよりもはるかに多くの情報が存在する可能性があることを示すために行いました。


状態がないので、技術的にはHATEOSとは思いません。
RibaldEddie

ええ、このプロセスの正確な言葉はわかりません。一般に、HATEOSはREST APIのリンクに使用されていますが、状態にも関係していることに同意します。実装の考え方は同じですが。ここでは、それは一例でどのように使用できるかについて、より多くのビットを参照してください。stormpath.com/blog/linking-and-resource-expansion-rest-api-tips
リュック・フランケン

それは良い考えです!
RibaldEddie

1
クライアントとAPI自体(内部APIなど)の間に凝集があるAPIを開発している場合、別のリソースへのリンクを提供するよりも、ネストされた(またはフラット化された)応答を返す方が意味があります。望ましくない場合があります。
ブルーノ

@brunoはい、ただし制限があります:大規模なシステムでは、すべての関連オブジェクトを完全に提供することはできません。デフォルトで含めるフィールドは任意です。APIの使用法に基づいて選択できます。したがって、この場合、何百ものフィールドを持つプラットフォームがあるかもしれませんが、ユースケースはプラットフォームを選択するための選択ボックスを示しています。次に、プラットフォームの名前を含めることは理にかなっていますが、たとえばプラットフォームの財務上の詳細は必要ありません。
リュックフランケン

16

これは、REST API設計に関する基本的な質問の1つです。すべてのデザイナーは、初日にこの質問を自問します。申し訳ありませんが、答えは「それは依存します」です。それぞれのアプローチには長所と短所があり、決定を下してそれを実行するだけです。


10
これはまったく役に立ちません。OP自身は「依存し、それぞれのアプローチには長所と短所がある」ことを知っていました。何に依存するかを説明するか、少なくとも例を挙げてください。
プラティックシンハル

5

次に、https://www.slideshare.net/stormpath/rest-jsonapisで提示されているアプローチ

つまり、ネストされたリソースを親リソースのリンクとして含め、一方、親エンドポイントに展開パラメーターを提供します。

私の意見では、これはほとんどの場合、効率的で柔軟な方法です。


2
私はこのアプローチが好きです。不思議に思う人のために、これはリンクされたスライドショーのスライド57から始まります。
アダムプロッチャー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.