PATCH Complex Data Structures


#1

Hi all - I’ve got a complex resource which multiple nested one-to-many relationships, which is allowed by the spec: “Complex data structures involving JSON objects and arrays are allowed as attribute values”.

Data looks roughly like this:

{
  "type": "contracts",
  "id": "9b0ac85e-a74f-4d4a-8248-33e0ae3a137",
  "attributes": {
    "name": "My Contract Name",
    "startYearAndMonth": "2017-04",
    "services": {
      "Service Name 1": {
        "name": "Service Name 1",
        "incomeStreams": {
          "Training": {
            "name": "Training",
            "dataPoints": {
              "2017-04": { "value": 143987 },
              "2017-07": { "value": 134936 }
            }
          },
          "Sales": {
            "name": "Sales",
            "dataPoints": {
              "2017-04": { "value": 3454565 },
              "2017-07": { "value": 5464566 }
            }
          }
        }
      },
      "Service Name 2": {
        "name": "Service Name 2",
        "incomeStreams": {
          "Training": {
            "name": "Training",
            "dataPoints": {
              "2017-04": { "value": 143987 },
              "2017-07": { "value": 134936 }
            }
          },
          "Sales": {
            "name": "Sales",
            "dataPoints": {
              "2017-04": { "value": 3454565 },
              "2017-07": { "value": 5464566 }
            }
          }
        }
      }
    }
  }
}

I’m struggling with adding or changing a single data point in a PATCH request. Over-writing the entire services attribute feels unnecessarily brute force - harder to implement (need to over-write all that data) and more prone to conflict with concurrent editing. Can I use JSON Patch for this purpose and still be JSON API compliant? It needs a different media type - application/json-patch+json.

The alternative I’ve come up with is to model services, incomeStreams and dataPoints as separate resources - then I can POST to the dataPoints collection or PATCH an existing dataPoint in isolation. But here I’m feeling the pain of creating a Contract in the first place - at the moment it’s a single POST to /contracts, but it would then need to be a barrage of POST requests to create each child item. As they are pure child, one-to-many relationships (no service is owned by another contract, no income stream by another service, no data point by another income stream) this seems overkill.

Grateful for any advice - I failed to find any advice on this score when searching.


#2

Rob, JSON Patch is not your answer, {json:api} compound documents are!

You already have the right notion in your head via the alternative you offered. The problem you mentioned is actually not a problem at all, you can create compound resources and dependent resources using a compound document as long as you supply the UUID for the newly created resource and use it as reference for your POST. The domain knowledge of the exclusive relationship between a service and a contract is clouding the picture for you as the design itself shouldn’t project that as a consideration as it could change later.

Let us know how it goes!


#3

Thanks very much - it wasn’t clear to me that a compound document could be a request entity as well as a response one. I will try that.