Should JSON Api attributes element contain nested objects?

This is the first time we are using JSON API in our projects and according to specification on their web, this is what a regular JSON API response should look like

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "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"}
      }
    }
  }],
  "included": [
    {
      "type": "people",
      "id": "42",
      "attributes": {
        "name": "John",
        "age": 80,
        "gender": "male"
      }
    }
  ]
}

We are not sure, should attributes in data be always flat, or attributes could also contain nested objects such as location for example

"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",
          "location": 
          { 
             "lat": "0.00",
             "long": "0.00"}
        },
1 Like

I don’t think the specification explicitly forbids that, but in your case I would make location a relationship. I would make your API for flexible. For example, you could retrieve a list of articles written about a certain place with /locations/id/articles.

The specification actually does allow for it;
http://jsonapi.org/format/#document-resource-object-attributes

Complex data structures involving JSON objects and arrays are allowed as attribute values.

I think your approach is fine in this case.

3 Likes

Completely agree. Either approach is acceptable.

When I embed complex data structures in attributes,
do I need to use the “types” and "attributes"
in each nested object
like in this example:

{
"data": [
    {
      "type": "dogs",
      "id": "3f02e",
      "attributes": {
        "name": "doggy",
        "body": {
          "type": "bodies",
          "attributes": {
            "head": "small",
            "type": "heads",
            "legs": [
              {
                "type": "legs",
                "attributes": {
                  "position": "front",
                  "side": "right"
                }
              },
              {
                "type": "legs",
                "attributes": {
                  "position": "front",
                  "side": "left"
                }
              }
            ],
            "fur": {
              "type": "fur",
              "attributes": {
                "color": "brown"
              }
            }
          }
        }
      }
    }
  ]
}

or can I use the simpler:

{
  "data": [
    {
      "type": "dogs",
      "id": "3f02e",
      "attributes": {
        "name": "doggy",
        "body": {
          "head": "small",
          "legs": [
            {
              "position": "front",
              "side": "right"
            },
            {
              "position": "front",
              "side": "left"
            }
          ],
          "fur": {
            "color": "brown"
          }
        }
      }
    }
  ]

?

Yes the specification allows nested complex types in attributes of an individual resource, BUT the complex type can not be another resource. See for example Clarification on Resources Composed of Other Resources in the json:api forum for details on this topic. If the nested type is another resource, favor a relationship instead. A corollary to this is do not include “foreign keys” in resources, again instead favor relationships between resources that abstract foreign keys away.

From a purely design perspective (bike shedding here we GO!) I would say you would be able to do this for a string location perhaps, but I’m not sure how helpful the sub resources would be at /location/-33.234235,151.247592/…etc

I am facing the same issue @junkoo. I am thinking of keeping the same format in the nested (non-resource) object, i.e type, attributes, and relationships, simply because in my use case, the nested non-resource object can have resource objects as relationships of its own! I’m not sure the spec covers this use case, but I’m pretty sure it doesn’t expressly forbid it.

It looks like your API needs a design makeover.

Fwiw I ended up converting the non-resource children to resources, which greatly simplified matters.

2 Likes