I’m struggling to work out how to use hypermedia to deep link to a specific resource.
I have a single page app that respects browser history - so you can bookmark say /contracts/<id>/dashboard. There are admin users who can see any /contracts/<id>, of which there are potentially many - too many to return as relationships of the user resource. The single page app’s URL structure doesn’t necessarily reflect the REST API’s URL structure, and it seems like a violation of hypermedia principles to couple them so tightly anyway.
I know I can just construct the REST url by appending <id> to the /contracts link, but it seems like that’s breaking hypermedia principles too, as the client is tightly coupled to a particular URL format. I see that JSON API used to support URI Template, but it appears this is no longer the case. Can someone point me at current advice for solving this issue?
First off, apologies for the late response because this is something I would have loved to jump on had I had the time. I’m going to have to make a few assumptions as I’m not sure of your entire situation, so I’ll try to point them out as I make them.
One of the things I understand about SPA is the URL binding is a way to expose and orient around the state of the application itself within the browser as a deep link to the SPA state. This you rightly point out is not the same thing as linking to a resource being consumed from the REST API and they should not be the same. What you can do is have the client retrieve the contracts by ID themselves by searching the user relationship contracts by the ID which is deep linked in the bookmark.
Your API could store the contract resources anywhere, the client would first query for the location of contract resources if it was expired or not yet cached locally, then query the root resource for the ID itself, which would make the REST API URLs for the resource meaningless.
The flow would look something like this.
browser GET http://example.org/webapproot/contracts/{id}/dashboard Deep linked from bookmark. triggers GET http://example.org/api/ to retrieve JSON Home for current contract root, or use unexpired cached URL. triggers GET http://example.org/api/naliflaisdfasdlijad?filter[id]={id} The URL is opaque, but the service said contract resources are found there.
Yes, the reason to not use the canonical ID in the link is because that would imply the client is building a URL, which it shouldn’t ever do. It should be use the semantics its given (filter) to search for the URL it has, and since ID is a required item in the resources of a {json:api} document, you should be able to rely on that attribute being present and filterable.