web-dev-qa-db-ja.com

スプリングレストコントローラーが特定のフィールドを返す

私は、Spring MVCを使用してJSON APIを設計するための最良の方法を頭で試してきました。ご存じのとおり、IOは高額なため、クライアントに必要なものを取得するために複数のAPI呼び出しを行わせたくありません。ただし、同時に台所の流しを返します。

例として、IMDBに似たゲームAPIに取り組んでいましたが、代わりにビデオゲーム用でした。

ゲームに接続されているすべてのものを返すと、次のようになります。

/ api/game/1

{
    "id": 1,
    "title": "Call of Duty Advanced Warfare",
    "release_date": "2014-11-24",
    "publishers": [
        {
            "id": 1,
            "name": "Activision"
        }
    ],
    "developers": [
        {
            "id": 1,
            "name": "Sledge Hammer"
        }
    ],
    "platforms": [
        {
            "id": 1,
            "name": "Xbox One",
            "manufactorer": "Microsoft",
            "release_date": "2013-11-11"
        },
        {
            "id": 2,
            "name": "PlayStation 4",
            "manufactorer": "Sony",
            "release_date": "2013-11-18"
        },
        {
            "id": 3,
            "name": "Xbox 360",
            "manufactorer": "Microsoft",
            "release_date": "2005-11-12"
        }
    ],
    "esrbRating": {
        "id": 1,
        "code": "T",
        "name": "Teen",
        "description": "Content is generally suitable for ages 13 and up. May contain violence, suggestive themes, crude humor, minimal blood, simulated gambling and/or infrequent use of strong language."
    },
    "reviews": [
        {
            "id": 1,
            "user_id": 111,
            "rating": 4.5,
            "description": "This game is awesome"
        }
    ]
}

しかし、彼らはこのすべての情報を必要としないかもしれませんが、その後再び必要になるかもしれません。すべてを呼び出すことは、I/Oとパフォーマンスから悪い考えのようです。

リクエストにincludeパラメータを指定することで考えました。

たとえば、インクルードを指定しなかった場合、返されるのは次のとおりです。

{
    "id": 1,
    "title": "Call of Duty Advanced Warfare",
    "release_date": "2014-11-24"
}

しかし、それはあなたがあなたの要求がこのようなものになるであろうすべての情報が欲しいです。

/api/game/1?include=publishers,developers,platforms,reviews,esrbRating

このようにして、クライアントは必要な情報量を指定できます。ただし、Spring MVCを使用してこれを実装するための最良の方法は、少し途方に暮れています。

コントローラーはこんな感じだと思います。

public @ResponseBody Game getGame(@PathVariable("id") long id, 
    @RequestParam(value = "include", required = false) String include)) {

        // check which include params are present

        // then someone do the filtering?
}

オプションでGameオブジェクトをシリアル化する方法がわかりません。これは可能ですか? Spring MVCでこれに取り組む最善の方法は何ですか?

ちなみに、私はシリアル化のためにジャクソンを含むSpring Bootを使用しています。

16
greyfox

Gameオブジェクトを返す代わりに、Map<String, Object>としてシリアル化し、マップキーが属性名を表すようにすることができます。したがって、includeパラメーターに基づいてマップに値を追加できます。

@ResponseBody
public Map<String, Object> getGame(@PathVariable("id") long id, String include) {

    Game game = service.loadGame(id);
    // check the `include` parameter and create a map containing only the required attributes
    Map<String, Object> gameMap = service.convertGameToMap(game, include);

    return gameMap;

}

例として、次のようなMap<String, Object>がある場合:

gameMap.put("id", game.getId());
gameMap.put("title", game.getTitle());
gameMap.put("publishers", game.getPublishers());

次のようにシリアル化されます。

{
  "id": 1,
  "title": "Call of Duty Advanced Warfare",
  "publishers": [
    {
        "id": 1,
        "name": "Activision"
    }
  ]
}
12

私の答えがかなり遅くなることに注意してください:Projectionsを確認することをお勧めします。

あなたが求めているのは、どのような予測なのかです。

Springについて質問しているので、これを試してみます: https://docs.spring.io/spring-data/rest/docs/current/reference/html/#projections-excerpts =

3
yaccob