Skip to content

Instantly share code, notes, and snippets.

@kevburnsjr
Created September 27, 2017 15:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevburnsjr/2105cf1316ad16a3f740773b10c06829 to your computer and use it in GitHub Desktop.
Save kevburnsjr/2105cf1316ad16a3f740773b10c06829 to your computer and use it in GitHub Desktop.
I strongly suspect that most clients are incapable of correctly handling transitions to APIs provided by other domain names.
If we change this ... to this ...
__links__: {
"subscriptions": "/core/accounts/{id}/playheads"
}
__links__: {
"subscriptions": "https://playhead-api.vrv.co/accounts/{id}"
}
... I doubt that all our clients would respond appropriately.
Many are probably concatenating the path onto the base API url.
If we tried to do this, many clients would probably break.
In order to route API requests to independent subdomains, we will need to version the API.
This could be achieved by upgrading clients to speak to a new entrypoint
We could make it clear that in order to use this new entry point, the client is required to handle absolute links appropriately.
But then we'd have 2 (or more) entry points to maintain indefinitely.
Another way to handle this which is often used by APIs which implement REST would be using mediatypes.
Right now we're serving all API responses as either application/json or text/plain.
We could (and should) formalize our mediatype by returning responses which can be used to identify the structure of the response.
Clients wishing to accept absolute URLs as links can request the new API version at the same entrypoint with an accept header indicating with which version of the API they wish to interact.
accept: application/vnd.vrv.v1+json
Responses to requests for the new media type would receive an appropriate content type in response
content-type: application/vnd.vrv.v1+json
This is the way Github does it in their API.
https://developer.github.com/v3/media/ꜛ
This is a sound approach, but we will still want to transition the entry point to a new canonical URL sometime soon, otherwise we will be stuck with /core/index as our entrypoint forever.
I recommend transitioning clients to
https://api.vrv.co/
as the new entry point.
In the meantime, we can proceed with implementation of the new content type API evolution strategy while the Core API is still serving requests from both Core and new services identified by the /core/index entry point.
---
The most brittle and difficult to change aspect of HATEOS is state transition flow.
Each client has drawn their own map of our services based on what it expects to find after it follows a link.
A typical HATEOAS client looks something like this
< GET /entrypoint
> 200 - Read json response and find the link relationship I care about
< GET /that-rel-link
> 200 - Read API response and follow another rel I expect to be there
< POST /the-think-I-actually/care-about
> 201 - Done
These transitions from link-rel to link-rel serve as the client's substitute for hard coded urls.
If you try to change those rel paths, your client's map is no longer accurate and they become lost.
Mike Amundsen's application/Maze+XML from Building Hypermedia APIs with HTML5 and Node is a great illustration of this.
http://amundsen.com/media-types/maze/ꜛ
Your API is a maze and your clients have to solve the maze so they can hard code the rel maps before they can deploy their client.
If you change the maze, the client may no longer be able to find the resources it needs to do its job.
Entry Points
---
If we have a number of public facing Hypermedia APIs rather than just one, it may be tempting to give each service it's own entry point.
In some sense, every hypermedia endpoint is a potential entry point.
You should be able to hop in at any point in the maze and make your way through.
However, APIs will often explicitly define their entrypoints as those which are most unlikely to change.
In the long run, we may want to consider altering our state transition flow in future generations of the API.
For instance, the permanent root endpoint http://api.vrv.co/ may decide it wants to defer all playhead related navigation to http://playhead-api.vrv.co/ to allow that service to evolve its own state transition flows.
So we might turn this ... to this ...
GET http://api.vrv.co/
__links__: {
"client_config": "http://client-api.vrv.co/config",
"cms_index": "http://cms-api.vrv.co/v1/US/M3/{+channel_id}",
"usernames": "http://account-api.vrv.co/usernames",
// ...
}
GET http://api.vrv.co/
__links__: {
"client": "http://client-api.vrv.co/",
"cms": "http://cms-api.vrv.co/",
"account": "http://account-api.vrv.co/",
// ...
}
In order to solve this new maze, the client would need to make an extra hop to each service in order to find the new config, index and usernames link-rels.
The advantage being that individual public facing APIs would have the opportunity to evolve their own internal URL structure as necessary.
Conclusion
---
Every time a client solves a relationship maze to navigate a REST API's link relationships to find the resources it cares about, that map is bound to the mediatype.
HATEOAS is about not just about relinquishing control of URLs to the server, it is also about evolving transition flows using mediatypes.
Our present media type (v0) has its own relationship maze even though it's not formally associated with a hypermedia type.
If we ever need to break our maze, clients will need to be upgraded to draw new link relationship maps for the new mediatype.
Thanks for listening.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment