2

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?

2

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:

2

The second approach of "Embedded Objects" is more extended & useful when working with complex JSON structures. A JSON structure might contain one or more of the following valid types: string, number, object, array, true, false or null. Being Object a JSON structure, it means a JSON is thought as complex structure of key-value pair objects nested as it's required. Another thing, repeating the same base URL as in the SWAPI example is not considered a good practice.

enter image description here

  • I disagree with "repeating the same base URL as in the SWAPI example is not considered a good practice". If you embed the full URL you decouple the client and the server: the client just follows whatever URL is in the response, and you can change the URL scheme in the server (different path, domain, etc.) without breaking compatibility with existing clients. – Armando Garza Sep 10 '18 at 19:51
  • 1
    See: json-schema.org/understanding-json-schema/structuring.html. «When writing computer programs of even moderate complexity, it’s commonly accepted that “structuring” the program into reusable functions is better than copying-and-pasting duplicate bits of code everywhere they are used. Likewise in JSON Schema, for anything but the most trivial schema, it’s really useful to structure the schema into parts that can be reused in a number of places. This chapter will present some practical examples that use the tools available for reusing and structuring schemas....» – ArBR Sep 10 '18 at 21:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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