Composition resource with 'type' information


#1

I read thru few discussion on this forum, but still don’t have clear understanding of how to include ‘composition’ resources that should carry type information.

I assume the definitions:

  • ‘composition’: the parent resource contains a child resource which does not exist outside the lifecycle of the parent resource
  • ‘aggregation’: the parent resource references another resource which lifecycle is independent of the parent resource, and it may outlive the parent resource

In the example below, ‘person’ resource has 2 eyes (composition) and a spouse (aggregation).
‘spouse’ resource aggregation is a good fit for the ‘relationships’ section, as it references independent resource with the unique id.
leftEye and rightEye don’t fit into the ‘relationships’ section, as they are not independent objects and they don’t have unique ids. The straightforward solution is to include them into person’s ‘attributes’ section, as shown below.

The problem is that there is no way to specify that leftEye and rightEye are of type ‘eye’. Such additional ‘type’ information may allow parser to be smarter about what it is parsing/add additional parsing logic/etc.

From reading the spec, it is not clear how I should deal with such a problem. Any advice will be appreciated.

{
  "data": {
    "id": "1",
    "type": "person",
    "links": {
      "self": "http://example.com/person/1"
    },
    "attributes": {
      "fullName": "Mike Wazowski",
      "leftEye": {
        "colour": "blue"
      },
      "rightEye": {
        "colour": "blue"
      }
    },
    "relationships": {
      "spouse": {
        "links": {
          "self": "http://example.com/person/1/spouse",
          "related": "http://example.com/person/2"
        },
        "data": {
          "type": "person",
          "id": "2"
        }
      }
    }
  }
}

#2

You can simply add a type key, like so:

{
  "data": {
    "id": "1",
    "type": "person",
    "links": {
      "self": "http://example.com/person/1"
    },
    "attributes": {
      "fullName": "Mike Wazowski",
      "leftEye": {
        "type": "eye",
        "colour": "blue"
      },
      "rightEye": {
        "type": "eye",
        "colour": "blue"
      }
    },
    "relationships": {
      "spouse": {
        "links": {
          "self": "http://example.com/person/1/spouse",
          "related": "http://example.com/person/2"
        },
        "data": {
          "type": "person",
          "id": "2"
        }
      }
    }
  }
}

The only keys that are reserved in object-valued attributes are links and relationships (see quote below) and there’s been some efforts to allow those too.

Complex data structures involving JSON objects and arrays are allowed as attribute values. However, any object that constitutes or is contained in an attribute MUST NOT contain a relationships or links member, as those members are reserved by this specification for future use.


#3

Thank you for your reply.

The problem with the above solution is that there is no way to distinguish ‘type’ attribute from all other object attributes. Not to mention it is not part of the jsonapi specification.

I should have mentioned in my original post that I am not only after a solution, but I am also after a solution that will be understood by anyone using jsonapi specification, as otherwise it becomes non-complaint change, so not much point using specification anyway.


#5

yet another attempt to solve the problem, thanks to Josh for some bright ideas :wink:

So, one of the possible solutions is:

  • composition is a relationship, so complex object attributes are moved from the ‘data’ to ‘relationships’ section
  • composition relationship will have ‘meta’, with attribute ‘composition’ set to true
  • as ‘resource linkage object’ may only contain id/type, but not data, the composition object will be included in the ‘included’ section
  • as ‘included’ section contains an array of ‘resource object’(s), the composition attribute may have links to another resource. An example is: person’s address (composition attribute) may have link to a country resource.

the example:

{
  "data": {
    "id": "/person/1",
    "type": "person",
    "links": {
      "self": "http://example.com/person/1"
    },
    "attributes": {
      "fullName": "Mike Wazowski"
    },
    "relationships": {
      "leftEye": {
        "meta": {
          "composition": true
        },
        "data": {
          "id": "/person/1/leftEye",
          "type": "eye"
        }
      },
      "rightEye": {
        "meta": {
          "composition": true
        },
        "data": {
          "id": "/person/1/rightEye",
          "type": "eye"
        }
      },
      "spouse": {
        "links": {
          "self": "http://example.com/person/1/spouse",
          "related": "http://example.com/person/2"
        },
        "data": {
          "type": "person",
          "id": "/person/2"
        }
      }
    }
  },
  "included": [
    {
      "type": "eye",
      "id": "/person/1/leftEye",
      "attributes": {
        "colour": "blue"
      }
    },
    {
      "type": "eye",
      "id": "/person/1/rightEye",
      "attributes": {
        "colour": "blue"
      }
    }
  ]
}

#6

@ekozynin example look good for get however what about post / patch? If person needs to be created how the structure will look like? Can POST have included? or do you think this will be in data collection?