JSON REST Responses – Handling Embedded Objects

Architecturejsonrest

I've been doing some research on RESTful architectures and JSON responses. I'm trying to understand which method of laying out JSON responses is "correct" or if they are both acceptable.

For instance, using the swapi, I've seen JSON responses that reference URIs for embedded objects:

{
  "name": "Luke Skywalker",
  "height": "172",
  "mass": "77",
  "hair_color": "blond",
  "skin_color": "fair",
  "eye_color": "blue",
  "birth_year": "19BBY",
  "gender": "male",
  "homeworld": "https://swapi.co/api/planets/1/",
  "films": [
    "https://swapi.co/api/films/2/",
    "https://swapi.co/api/films/6/",
    "https://swapi.co/api/films/3/",
    "https://swapi.co/api/films/1/",
    "https://swapi.co/api/films/7/"
  ],
  "species": [
    "https://swapi.co/api/species/1/"
  ],
  "vehicles": [
    "https://swapi.co/api/vehicles/14/",
    "https://swapi.co/api/vehicles/30/"
  ],
  "starships": [
    "https://swapi.co/api/starships/12/",
    "https://swapi.co/api/starships/22/"
  ],
  "created": "2014-12-09T13:50:51.644000Z",
  "edited": "2014-12-20T21:17:56.891000Z",
  "url": "https://swapi.co/api/people/1/"
}

I've seen other JSON responses formatted as follows, where the object is "embedded" in the response — see "homeworld" below:

{
  "name": "Luke Skywalker",
  "height": "172",
  "mass": "77",
  "hair_color": "blond",
  "skin_color": "fair",
  "eye_color": "blue",
  "birth_year": "19BBY",
  "gender": "male",
  "homeworld": {
    "name": "Tatooine", 
    "rotation_period": "23", 
    "orbital_period": "304", 
    "diameter": "10465", 
    "climate": "arid", 
    "gravity": "1 standard", 
    "terrain": "desert", 
    "surface_water": "1", 
    "population": "200000"
  },
  "created": "2014-12-09T13:50:51.644000Z",
  "edited": "2014-12-20T21:17:56.891000Z",
  "url": "https://swapi.co/api/people/1/"
}

Is one of these considered more "correct" than the other, or is it really based on the requirements of the particular solution?

Best Answer

As with many design issues the answer is "it depends".

In most cases you have to find a balance between:

  1. Big response: embed everything, even if some clients don't use it
  2. Many requests: don't embed anything and let the clients make one extra request for each additional resource that they need.

I don't think that either of these is "more correct" than the other.

There are a few standards like JSON API and HAL that attempt (among other things) to solve this problem. They both have the concept of "included" (or embeded) resources which are requested by the client, e.g. for JSON API

If you request GET /articles you would receive:

{
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON API paints my bikeshed!",
      "body": "The shortest article. Ever.",
      "created": "2015-05-22T14:56:29.000Z",
      "updated": "2015-05-22T14:56:28.000Z"
    },
    "relationships": {
      "author": {
        "data": {"id": "42", "type": "people"},
        "links": {
          "self": "http://example.com/articles/1/author"
        }
      }
    }
  }]
}

And you could also do GET /articles?include=author

{
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON API paints my bikeshed!",
      "body": "The shortest article. Ever.",
      "created": "2015-05-22T14:56:29.000Z",
      "updated": "2015-05-22T14:56:28.000Z"
    },
    "relationships": {
      "author": {
        "data": {"id": "42", "type": "people"},
        "links": {
          "self": "http://example.com/articles/1/author"
        }
      }
    }
  }],
  "included": [
    {
      "type": "people",
      "id": "42",
      "attributes": {
        "name": "John",
        "age": 80,
        "gender": "male"
      }
    }
  ]
}

Which adds an "included" key that contains more resources. This way the client can decide for each use case.

Of course, this puts an extra burden in the client to parse the response since it's more complex than simple data structures (there are libaries for that).

Here are some useful reads:

Related Topic