54

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.

6
  • 6
    What objections, if any, do you have returning embedded objects? Returning embedded objects individually from different endpoints is going to get pretty damn annoying (not to mention slow). Feb 9, 2015 at 0:21
  • 2
    Personally I have no objections to it. I'm just not aware of what is considered best practices. A colleague claims working with embedded objects in AngularJS is not straight forward and eventually I would like either Ember of AngularJS app to consume the API. I don't know enough about Angular or Ember to know if that will have an impact or not.
    – greyfox
    Feb 9, 2015 at 0:24
  • 3
    The answer is going to depend on whether you wish to return domain objects, DTO's, ViewModel objects, or KitchenSink objects. Which object you're returning is very likely going to be determined by what your application needs, and how said object behaves over the Internet. Example: if you're trying to fill a web page with data from an invoice, very likely you're going to return an object containing everything you need (unless you plan on AJAXing in the line items, or something like that). Feb 9, 2015 at 0:26
  • 1
    Which is this case when you request a game you would likely want to know the genres, platforms, and ESRBRating. That makes sense. In terms of design from a Java perspective would you recommend having Entity package which has JPA entites, and then a domain package which is the business objects / DTO being return to the user?
    – greyfox
    Feb 9, 2015 at 0:30
  • 2
    Calls to the server are expensive. An API that requires you to send data using multiple calls will be slower than an API that lets you get everything in one call, often even when the latter returns unneeded information. Feb 9, 2015 at 1:21

2 Answers 2

14

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.

5
  • I don't think that's technically HATEOS since there is no state. Feb 9, 2015 at 7:14
  • Yeah, not sure the exact word on this process. HATEOS in general is being used for linking in rest API's but I agree it also has to do with state. Though the idea of implementation will be the same. Here you see a bit more about how it can be used by an example: stormpath.com/blog/linking-and-resource-expansion-rest-api-tips Feb 9, 2015 at 13:35
  • It's a good idea though! Feb 18, 2015 at 17:08
  • 2
    If you are developing an API where there is cohesion between client and the api itself (say an internal api), it might make more sense to return a nested (or flattened) response rather than provide links to another resource, which means more API requests which may be undesired.
    – B B
    Jun 24, 2016 at 9:22
  • @bruno yes but with a limit: On bigger systems you cannot or don't want to supply all related objects in full. The fields you include by default are arbitrary, you can select them based on the usage of your api. So in this case you might have platforms with hundreds of fields, the use case is showing a selectbox to choose a platform. Then it makes sense to include the name of the platform but it doesn't need the financial details of the platform for example. Jun 27, 2016 at 8:49
8

I second the approach presented here https://www.slideshare.net/stormpath/rest-jsonapis

In short, include the nested resource as links in the parent resource, meanwhile, provide an expand parameter in the parent endpoint.

In my opinion, this is a way which is efficient and flexible in most cases.

1
  • 3
    I like this approach. For anyone wondering, this starts at SLIDE 57 in the linked slideshow. Jul 7, 2018 at 21:11

Not the answer you're looking for? Browse other questions tagged or ask your own question.