Take the following URI's as an example:
/tracks
/tracks/:id
/playlists
/playlists/:id
/playlists/:id/tracks
I have a question about the last URI (/playlists/:id/tracks). How do I add extra information/context to the track objects in relation to it's parent playlist?
Examples of context:
All tracks have a created timestamp, play count and likes on a global scale. So my question is how would this information be added to the response of the endpoint.
I've come up with following for now:
{
"title" : "harder better faster stronger",
"artist" : "daft punk",
"likes" : 234252,
"created_at" : "2012-10-03 09:57:04"
"play_count" : 1203200035,
"relation_to_parent": {
"likes" : 5,
"created_at" : "2014-11-07 19:21:64",
"play_count" : 20
}
}
I've added a field called relation_to_parent which adds some context to the relation between the child and it's parent. I'm not sure though if this is a good way to do it. Hope to hear some other solutions.
By 1:n relations you can define a subresource. By n:m relations it is better to define a separate relationship resource. Note that these are just best practices, not standards.
Be aware that you can add links pointing to a different resource. According to the HATEOAS constraint you have to create hyperlinks if you want to expose an operation (for example getting another resource).
I don't think there is a 'one true way' to do this. Personally, I dislike adding the extra information like that, since you are giving a resource-plus, when you are looking for a resource. In any case, are 'likes' and 'created_at' and 'play_count' actually part of the relation to the parent, aren't they part of the track itself?
The two paths I usually see for this are:
/playlist/:id/tracks - returns a list of IDs (or URLs) for actual tracks, which you then fetch with /tracks/:track/playlist/:id/tracks - returns the actual tracks, as if you did both steps in 1 above.As for additional information, if it is not part of the tracks, you might do it as (any of these is valid):
/tracks/:track always returns the 'play_count' and 'likes', etc./tracks/:track/social_info or maybe /social_info/:track where it matches the track ID 1-to-1If you have actual relation information, then it depends if it is 1:1 or 1:N or N:1 or N:N. 1:1 or 1:N or N:1 you would probably reports as part of the resource itself, while N:N would either be part of the resource (JSON objects can have depth) or as a separate resource.
Personally, I have done all of the above, and find cleaner is better, even if it is multiple retrievals. But now we are delving into opinion....
EDITED:
There are lots of ways to do N:N, here are just some:
/playlist/:id/tracks/:track/social_info - which could be embedded or a link to another object/social_info/:playlist - more direct/social_info/playlist/:id if you might have different kinds of social infoPersonally (there is that word again; so much of this is personal preference and opinion), every time I have tried using deeper paths, thinking something only makes sense in a parent context, I have found myself ending up making its own resource for it, and linking back, so the 2nd or 3rd option ends up being what I do, with the first linking to it (either convenience to retrieve it or retrieve a list of it).
Mostly, that has not been because of constraints on the server side - e.g. when I write in nodejs, I use http://github.com/deitch/booster which handles multiple paths to the same resource really easily - but because client side frameworks often work better with a one true path.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With