Complex structures with action links in substructures


#1

Hi Everyone,

I’ve been working through designing a solution for a problem and have decided to use the json:api media type. I’ve not done so in the past so am still coming to terms with the specification.

I’ve used mason in the past and the example below is an extract from one of those designs.

So to where I am currently fuzzy on how to proceed:

In the payload for a user we have in the past used action links nested in the payload data to effect specific changes on that user.

This has worked very nicely to add a readability aspect to the API as well as some nice structured logic.

A great and simple example is physical addresses.

In the example users can share their belongings, and some people are lucky enough to have 2 homes that are a long way apart, so it makes sense for the user to have multiple addresses. its also likely that MOST of their things will live at the real home, not the winter home in aspen.

We want to be able to add and remove addresses and also set a given address as the primary.

So how I have handled this in the past looks like dis:

"title": "freddyB",
"firstName": "Fred",
"lastName": "Bassett",
"email": "freddyb@cartoons.com",
"gender": "M",
"bday": "1965-05-26",
"note": "time flies like an arrow, fruit flies like banana",
"relationship": {
	"state": "FRIEND",
	"trust": "FULL",
	"shareGroups": [
		"GLOBAL",
		"GOLF",
		"MUSIC"
	]
},
"primaryAddress": "1",
"addresses": {
	"items": [
		{
			"id": "0",
			"unitNo": "5",
			"streetAddress": "50 Bagner Road",
			"locality": "Brisbane",
			"region": "Queensland",
			"postalCode": "4001",
			"countryName": "Australia",
			"geometry": {"type": "Point", "coordinates": [102.0, 0.5]},
			"@navigation": {
				"is:set": {
					"type": "link",
					"href": "http://.../users/u35253/address?primary=0",
					"title": "Set this as primary address"
				},
				"is:delete": {
					"type": "void",
					"href": "http://.../users/u35253",
					"method": "DELETE",
					"title": "delete this address"
				},
				"edit": {
					"type": "json",
					"href": "http://.../users/u35253/addresses/0",
					"title": "Update this address.",
					"template": {
						"unitNo": "5",
						"streetAddress": "50 Bagner Road",
						"locality": "Brisbane",
						"region": "Queensland",
						"postalCode": "4001",
						"countryName": "Australia"
					}
				}
			}
		},

Its clear whats happening in, each address has some links to add or remove and (you cant see it here) the root @navigation element (links) includes the ability to add a new address.

We have consciously chosen to localise the storage of addresses for security reasons beyond the scope of this disucssion.

What is the best way to enact this in json:api as the specification states:

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.

My guess is that these belong in the resource object’s links member and initially i thought ok some kind of mapping like the type/id dealy should help identify the specific cases but I dont see how this is acomplished.

Any input on how best to handle this would be appreciated.

Cheers
b


#2

Sorry for the delayed response.

The links key in JSON API, even where it’s already allowed, isn’t yet a full hypermedia solution. For now, it’s only a way to offer a predefined set of links for common cases like pagination. The plan, though, is to expand it over time…hopefully to give it a one-to-one mapping with RFC 5986 links and to add write templates.

Therefore, my suggestion for now would be to just get rid of the the links all together. This shouldn’t be a problem, though, because JSON API already defines how clients should perform the actions your links are describing (namely, by PATCHing the primaryAddress field or the addresses array). You’ll lose the ability for a client to delete an address without having to resend the other addresses (since it’ll have to send the full address array in a PATCH), but otherwise all the functionality you want should be easily achievable.