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" } ] }
Being aware that my answer comes quite late: I'd recommend to look at Projections
.
What you're asking for is what projections are about.
Since you're asking about Spring I'd give this one a try: https://docs.spring.io/spring-data/rest/docs/current/reference/html/#projections-excerpts
A very dynamic way for providing different projections on demand is offered by GraphQL
. I just came across a very helpful article about how to use GraphQL
with SpringBoot
: https://www.graphql-java.com/tutorials/getting-started-with-spring-boot/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With