4 ms·
My opinionated design principle for RESTful APIs is to keep in mind that REST is just a style sheet of good practices and patterns as in, do not apply it blindl
by kh_hk 13y ago
My opinionated design principle for RESTful APIs is to keep in mind that REST is just a style sheet of good practices and patterns as in, do not apply it blindly and just use whatever makes sense.
From there, I have conflicting emotions with this:
Although the web generally works on HATEOAS type principles (where we go
to a website's front page and follow links based on what we see on the
page), I don't think we're ready for HATEOAS on APIs just yet.
I do not think "being ready" is an argument to use or not use HATEOAS. Sure, HATEOAS as defined by Roy Fielding contains a lot of clutter, but there's nothing bad if it makes sense to assume a client that does not know how to construct URLs. Generally I find it nice to have something similar to:
GET /fooes
{
"fooes": [
"foo": {
"bar": {
"some": "baz"
},
"name": "The Mighty Foo",
"id": "the-mighty-foo",
"href": "/fooes/the-mighty-foo"
},
...
]
}
- h2s 13y agoThere's a sliding scale of HATEOAS-ness. I've seen a much more extreme form of it described elsewhere. Mark Seemann (http://blog.ploeh.dk/2013/05/01/rest-lesson-learned-avoid-hackable-urls/ http://blog.ploeh.dk/2013/05/01/rest-lesson-learned-avoid-ha...) describes an approach that encrypts all URLs so that clients have no choice but to follow links because generating URLs from templates is impossible. So instead of http://foo.ploeh.dk/customers/1234/orders You'd have http://foo.ploeh.dk/DC884298C70C41798ABE9052DC69CAEE And you'd have to get that URL out of the response to another request you'd already made. I never liked this idea, and the linked article provides a really strong counterargument to this approach to HATEOAS. When browsing a website, decisions on what links will be clicked are made at run time. However, with an API, decisions as to what requests will be sent are made when the API integration code is written, not at run time. Could the decisions be deferred to run time? Sure, however, there isn't much to gain going down that route as code would still not be able to handle significant API changes without breaking.
- kh_hk 13y agoAbout the counterargument, yes, it does raise a good point (in fact, one that I skimmed through). Specially about changes and breaking. For instance, in the following document, what is to change in the href attribute? GET /fooes ... "foo": { "id": "the-mighty-foo", "href": "/fooes/the-mighty-foo", ... }, ... Surely, not much. Either /fooes/ changes to /foos/, in that case, the call to /fooes is broken anyway, or the id has changed, and needs to be handled with an HTTP 301 anyway. So no, there's not much to gain. But then again, I was just saying that the href attribute might make sense in some cases, with not much extra effort. Nobody is asking the clients to consume the href attribute, it just makes understanding the whole API easier. As of images, what would make more sense, to add an endpoint /images/10/view or directly use an href attribute pointing to http://s.foo.bar/1337.png http://s.foo.bar/1337.png ? My point is, in some cases it makes sense, just use it when it does. Just as one should not be encrypting URLs just because Mark Seemann feels it is within the holy grail of the Level 3 API as defined by Leonard Richarson [1], we should not be avoiding to make our APIs navigable. [1]: Don't get me wrong. What they say might make sense in non-trivial APIs, as always, REST is not an specification.
- veesahni 13y agoI agree that the href can help make understanding the API easier. If anything, it improves API explorability.
- smizell 13y agoI think we spend too much time trying to craft beautiful, descriptive URLs, where we should be spending our time crafting beautiful, descriptive responses. We try to make the URL describe to the developer what is being returned, when in reality, this should be dictated by media types and link relations. Take for instance the example above. Whether the URL is /images/10/view or /images/10.png, the developer has no idea what kind of resource that is without any media types or relations (the file extension != to the media type). In other words, you could use both URLs to return the same exact resource, and the client shouldn't care. You could even change back and forth between those URLs and the client should never flinch. This is actually a good example. Say you are serving a static PNG file at /images/10.png, linked in your server response (i.e. in some href like above). Say you want to change things up to do some type of logging on how many times the image has been viewed, so you write some code, create a response at /images/10/view, log views, and return the image with an image/png media type. You just did a really big API change and the client didn't have to be changed. Now if your client was dumber, and was crafting URLs as /images/{id}.png, you would break all of your clients if you did the above changes. This of course is really just the tip of the iceberg of what flexibility HATEOAS can bring.