32

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.

  • 5
    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). – Robert Harvey Feb 9 '15 at 0:21
  • 1
    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 '15 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). – Robert Harvey Feb 9 '15 at 0:26
  • 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 '15 at 0:30
  • 1
    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. – Steven Burnap Feb 9 '15 at 1:21
9

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.

  • I don't think that's technically HATEOS since there is no state. – RibaldEddie Feb 9 '15 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 – Luc Franken Feb 9 '15 at 13:35
  • It's a good idea though! – RibaldEddie Feb 18 '15 at 17:08
  • 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. – Bruno Jun 24 '16 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. – Luc Franken Jun 27 '16 at 8:49
15

This is one of those basic questions when it comes to REST API design. Every designer asks themselves this question on the first day. Sorry but the answer is "it depends". Each approach has pros and cons and you'll just need to make a decision and go with it.

  • 5
    This is not at all helpful. OP himself knew "it depends and each approach has pros and cons". You should explain on what things does it depend or at the very least give some example. – Pratik Singhal May 26 '18 at 4:11
5

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.

  • 2
    I like this approach. For anyone wondering, this starts at SLIDE 57 in the linked slideshow. – Adam Plocher Jul 7 '18 at 21:11

protected by gnat Sep 28 '17 at 11:11

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

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