I've been going through my head the best way to design a JSON API using Spring MVC. As we all know IO is expensive, and thus I don't want to make the client make several API calls to get what they need. However at the same time I don't necessarily want to return the kitchen sink.
As an example I was working on a game API similar to IMDB but for video games instead.
If I returned everything connected to Game it would look something like this.
/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"
}
]
}
However they may not need all this information, but then again they might. Making calls for everything seems like a bad idea from I/O and performance.
I thought about doing it by specifying include parameter in the requests.
Now for example if you did not specify any includes all you would get back is the following.
{
"id": 1,
"title": "Call of Duty Advanced Warfare",
"release_date": "2014-11-24"
}
However it you want all the information your requests would look something like this.
/api/game/1?include=publishers,developers,platforms,reviews,esrbRating
This way the client has the ability to specify how much information they want. However I'm kind of at a loss the best way to implement this using Spring MVC.
I'm thinking the controller would look something like this.
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?
}
I'm not sure how you would optionally serialize the Game object. Is this even possible. What is the best way to approach this in Spring MVC?
FYI, I am using Spring Boot which includes Jackson for serialization.
Instead of returning a Game
object, you could serialize it as as a Map<String, Object>
, where the map keys represent the attribute names. So you can add the values to your map based on the include
parameter.
@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;
}
As an example, if you have a Map<String, Object>
like this:
gameMap.put("id", game.getId());
gameMap.put("title", game.getTitle());
gameMap.put("publishers", game.getPublishers());
It would be serialized like this:
{
"id": 1,
"title": "Call of Duty Advanced Warfare",
"publishers": [
{
"id": 1,
"name": "Activision"
}
]
}