REST API Design – Should API Return Nested JSON Objects?

api-designdesignjsonrest

When it comes to JSON APIs is it good practice to flatten out responses and avoid nested JSON objects?

As an example lets say we have an API similar to IMDb but for video games. There are a couple entities, Game, Platform, ESRBRating, and GamePlatformMap which maps Games and Platforms.

Lets say you request /game/1 which fetches the game with ID 1 and it returns the game object with the platforms and esrbRating nested.

{
  "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"
  }
}

If you are using something like JPA/Hibernate it may automatically do this for you if it is set to FETCH.EAGER.

The other option is to simply the API and add more end points.

In that case when /game/1 is requested just the game object is returned.

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

If you want the platforms and/or ESRBRating you would have to call the following:

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

This method seems like it could potentially add several more calls to the server depending on what data the client needs and when they need it.

There was one last thought I had where you would have something like this returned.

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

However this assumes they don't need the IDs or whatever other information may be associated with those platform objects.

I asking in general what is the best way to structure your JSON objects returned from your API. Should you try to stay as close to your entities as possible, or is it fine to use Domain Objects or Data Transfer Objects? I understand the methods will have trade offs, either more work on the data access layer or more work for the client.

I would also like to hear an answer related to using Spring MVC as the backend technology for the API, with either JPA/Hibernate or MyBatis for persistence.

Best Answer

Another alternative (using HATEOAS). This is simple, mostly in practice you add a links tag in the json depending on your use of HATEOAS.

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: [] },
  ]
}

You can off course embed all data in all listing but that will likely be way too much data. This way you can embed the required data and then load more if you really want to work with it.

The technical implementation can contain caching. You can cache the platforms links and names in the game object and send it instantly without having to load the platforms api at all. Then when required you can load it.

You see for example that I added some form information. I did that to show you there can be much more information in a detailed json object than you would even want to load in the listing of games.