I've never understood this either. My API client isn't smart enough to follow links and write logic for me, so when they say "the client" can "discover", they must be referring to myself, and not my code? Well I'd much rather read documentation than click hyperlinks inside an API.
for example, the spec for the HTML media-type that when a client sees a link with the rel-type "stylesheet" is should fetch the resource using HTTP GET.
As REST requires that media-types be registered the idea would be that we would eventually get a set of media-types that cover things like audio playlists, and how to interact with them.
So any "intelligence" required by a client would be baked into the implementation of the media-type processor. Instead of "client libs" for specific web services, you would have a general media-type parser/processor which could be re-used by clients of different web services to process common media-types.
But apparently individual client libs for each web service that overloads JSON is better.
I mean, there are so many different types of resources and every API I interact with definitely invent their own. How often do you come across an API offering a playlist of music?
It can also be browse-able with a regular browser. If you visit it say with Firefox and go to .../api/ and the browser tells the backend it accepts text/html back, the service would return a list of sub-resources as proper hyperlinks. Pretty formatted json and so on. Might return a few items only not all if there are too many in a collection. After you see all sub-resources .../api/docs/ .../api/widgets/ etc. you navigate by clicking to any of those..
I have actually built that and it seemed like gimmick first but improved developer productivity quite a bit because the API is discoverable and provides live data (instead of just out-dated examples from docs that nobody updates.
Was it HATEOAS? I still don't know. But I knew it worked really nicely. Someone working on the backend could finish a feature and stick it in /api/newfeature/ a front-end developer would browser that get a sense of how it works, what data looks like and so on.
(Bonus points: figured a way to auto-generate docs from code comments from classes and modules and pushed them to the API resources, so now it is was self documented, and had live example and so on).
If you have an object which links to `/users/1/`, and want to change that URL to `/cool_users/1/`, what's the migration path?
Without HATEOAS, you need to update all your clients' code to now generate the new base URL `/cool_users/`. This means you'll need to version your API, so that old clients can continue to access the old-style endpoints in the transition period. (Note that for a business where your customers are making an API integration, this means you're imposing work on your customers).
With HATEOAS, you just need to update the URLs that are returned in your other endpoints. (Generally there is one well-known entry-point into your API, e.g. you return {"user_list": "/users/", ...} with your login token, for example). Now, assuming your clients were using `api.user_list`, that they received, they will without further modification fetch the `/cool_users/` endpoint, without requiring an update.
The one gotcha is if clients are holding on to the IDs of your API objects between API calls; in that case, you will break any code which expects to find those previously-returned members. But note, the worst-case here is that you need to version your APIs, which was the best-case without HATEOAS. In many cases you can get away with such a change without any client-facing changes.
No clients bother to do this, in the real world - they just hard code/compose the URLs that they need to use. Why make extra http calls when you don't have to? Why parse all the json-hal (or whatever) to "figure out" which URL to call next, when you don't have to?
Even if most clients did this, you can't enforce it, so not all of them will, so some will still break when you change URLs.
1) It makes manual testing annoying, 2) I have a nagging feeling that if my users are "doing it wrong" then maybe the API is doing it wrong...
Also I've been playing with autogenerating client implementations using autogenerated swagger specs, and that approach is incompatible with an actual opaque linked API. It would be nice to have the best of both worlds.
There's a good question about how long you can cache those URLs for as well; it's a non-starter for a client to have to traverse the whole tree from the root for every request. So can I cache the responses for the duration of my auth token, and get a new root node as part of my re-auth?
If you go down that route, now you need to maintain two versions again during migration (but you do keep the ability for 'well-behaved' clients to migrate versions without downtime).
As the sibling comment describes, you _can_ enforce this by obfuscating your URLs, but I've not had the guts to do that yet...
Another approach would be to write great client libraries yourself, so that you know that the clients are consuming the API correctly.
I don't think that the supposed benefits of HATEOAS actually materialise, in the real world.
Imagine for example that we decided that whenever you request a comment resource from my API then I promise to provide a link in the response called "upvote" which you can follow to upvote that comment.
We have agreed to a fixed interface but left plenty of details flexible.
Maybe we are experiencing heavy load: let's stop sending the "upvote" link - the clients should understand that in its absence the operation is not currently available.
Maybe we have implemented some load-balancing system which redirects clients to `fiji.api-server.com` or `romania.api-server.com` based on their geo-ip data: those clients need only hard-code one top-level API URL into their code and all other URLs come through successive API responses. Load-balancing happens automatically and can even change throughout a single session because the client follows the links instead of building its own URL.
Maybe we are running some test or gradual rollout of a new API or URL structure; as long as we provide those links and references the clients can follow the right path without needing to know about the changes. It's possible that we ended up moving comments from `api-server.com/api/threads/1337/comments/42` to `api-server.com/comments/what-do-you-kow-joe` and this won't break any client designed to follow the interface instead of the incidental details.
For what it's worth I think very few APIs come reasonably close to this design and maybe few even have much need to. REST and HATEOAS become much more important when someone is publishing a public API that many third parties will consume and the ability to introduce non-breaking changes and server-side control of different specifics is important.
/my 2¢
There's all kinds of other directions you can take this including quota enforcement, monitoring, auditing, and other resource-agnostic concerns. More radically, you can make these sorts of proxies reusable services that other people rely on to implement these behaviors. One of the primary motivations for REST in the first place was a standard interface that would allow for insertion of caches at arbitrary points in the Web without breaking everything (in the optimistic case at least). There's even HATEOS in the Cache-Control header, as the cache channels extension uses links to external resources to define the cache channels for resources
So the client will keep working even if a few months from now you want to change the link to something else. A simple example: if retrieving articles can be done by requesting this link "/articles", I can potentially change it in the future to "/v2/articles" and the client would still work.
I think this is also the theoretical promise of one approach to linked data/RDF.
In practice, I don't think it happens, and is not worth the conceptual and engineering overhead for the possibility of something that doesn't seem to be realistic to expect.
Instead of hard coding the subject hierarchy in templates (like "/topic/subtopic/"), you define a document type that exposes target elements as links (typically with a "rel" attribute identifying the type of element). The client can then navigate the logical hierarchy without requiring this to match the physical URLs (think: federation across departments; instead of having a template "/api/{department_id}/people/{employee_id}", the company can expose a directory document that aggregates links "link rel='employee' target='https://departmentX.company.com/arbitrary/hierarchy/employee... and "link rel='employee' target='https://othercompany.com/api/users/Doe+John'").
The type of linked resources must of course be aligned; there's no magic involved. Instead of the client having out-of-band knowledge about the hierarchy, the client must have out-of-band knowledge about the used document types containing the links.
The client knows what and how it can access on the behalf of the authenticated user. Examples:
Representation for a user with no privileges:
{
"articles": [{
"id": 123
"title": "A title",
"links": {
"self": {
"href": "http://blog.com/articles/123",
"methods": ["GET"]
}
}
}],
"links": {
"self": {
"href": "http://blog.com/articles",
"methods": ["GET"]
}
}
}
Representation for a user who is authorized to add/edit/delete articles: {
"articles": [{
"id": 123
"title": "A title",
"links": {
"self": {
"href": "http://blog.com/articles/123",
"methods": ["GET", "DELETE", "PUT"]
}
}
}],
"links": {
"self": {
"href": "http://blog.com/articles",
"methods": ["GET", "POST"]
}
}
}
This reduces the authorization logic on the client side.Have you ever used a web browser? You know how the browser uses media-type to determine how to handle content referenced by a URI? That's what HATEOAS is supposed to be useful for: links identify and locate resources, resource type information tells you what kind of resource it is. The only out-of-band information you should need for an idealized REST API is information on the protocol used (e.g., HTTP) and information on the resource types (media types for HTTP) of the resources used.
(Really, if you want to understand any component of REST, its probably easiest to ask "what is this used to accomplish in the HTTP-based web", since REST is essentially a generalization of an idealized version of the HTTP-based web.)
Web browsers are extremely generalized: they display arbitrary HTML, submit arbitrary forms, download arbitrary images, download and run arbitrary JS/CSS.
Most APIs are intended for more specific uses than "all of HTML". Hypermedia is very useful for browsers, but I wouldn't extend that to say, my Imgur clone API.
The question is whether people are making APIs to be consumed by general purpose tools, not whether they are making general purpose tools.
But, yes, there's a quite valid argument that REST isn't always the right architectural style for an API.
Which isn't an excuse to use the term "REST" for things that aren't REST, which just confused the issue.
* For related resources (imagine a DB FK), instead of listing a uuid you point a link to the location of that resource. This means if the resource location changes the client doesn't need to be updated, it just uses whatever the new link is.
* Methods listed can drive available actions, e.g. imagine you have both mutable and immutable objects, a smart client could reason if PATCH is available then a UI element can be spawned allowing the user to modify this resource.
This is useful in a single client scenario whereby the API schema can be modified to a certain extent without the need to modify the client. It is also useful in a multi-client scenario (either distinct or versioned clients) for ensuring consistency between clients as you no longer need to ensure all clients are modified to use the new schema.
At least, this is how I understood it, I haven't tried it in practice.
Your client then can machine read that documentation (which can have long-lived cache headers or be immutable, so your client doesn't spend it's whole time re-checking documentation).
There will be a set of definitions that the client understood when it was coded, and by checking a payload for matching meanings, it can consume the information.
If it finds something it doesn't understand, it could even try to take some compensating action (e.g. suppose it's a client which displays images to it's users, and it encounters a new type of image format. It could perhaps look up a registry of javascript canvas image renderers and download suitable code to display the new image).
The general idea of returning links to related resources and/or actions is fine and good, but the rhetoric tends to go further, to ecompass claims like the API being "self-documenting" or amenable to a universal client. It always seems to me that this Big Idea of just presupposes the existence of a "smart" client that can really understand the links, one that there doesn't seem to be much sign of.
GitHub's API proudly notes its use of hypermedia and URL Templates in its responses, but I still have go read the documentation to decide what link I need to use, and what needs to fill into those variable slots in the URLs. The template doesn't do much for me that text in the documentation saying "these GET paramters are accepted/required" wouldn't just as well.