I edited this to be correct. I incorrectly assumed that WADL didn’t support HATEOAS. Apologies Marc Hadley
A friend, colleague, and old mentor of mine, Steve Vinoski (he also introduced me to REST) talks a little bit about his RESTful experiences with his current development team. It is cool to hear that this stuff is working in action specifically:
For example, I just finished a meeting a couple of hours ago where some client code needs to interact with a particular part of my system via HTTP, but wants XML instead of JSON currently provided. Simple — it’s just a different representation of the same resources…..[snip] Can you imagine the hoops one would have to jump through with typical RPC-oriented systems [snip]?
He also goes on to talk about how client developers asked for a “REST-like-interface”:
[snip] A document listing all resource URIs, and for each one, the HTTP verbs that apply to it, the representations available from it, and what status codes to expect from invoking operations on it….[snip]for a proper RESTful system, you don’t need a document like that, at least not the type of document they’re asking for.
My guess is that his developers are looking for something a WSDL-like document, or something like WADL. What Steve is getting at is that you don’t need a WADL because HATEOAS allows you to discover how to interact with your services. In abrowser-based, HTML-based world, this is definately true. HTML documents are self-describing and renderable by your browser. Humans can look at a rendered page and now how to interact, serf, and fill and post forms. Machine-based clients are different though. They usually exchange more machine-friendly formats like XML and JSON. They can’t make dynamic decisions and need to know ahead of time what interactions are available and how to perform the interactions. The de facto way of doing this has been to embed somethign like an Atom link into a document:
<order id="123"> <amount>$123.45</amount> <atom:link rel="CANCEL" href="http://orders.com/orders/123/cancelled"/> <atom:link rel="PAYMENT" href="http://orders.com/orders/123/payment" type="application/xml"/> ... </order>
In Atom land, interactions are defined as named, logical, relationships which provide a URI and expected type. While machine-based clients are not going to be able to make many dynamic decisions on a self-describing document, there are a lot of advantages to HATEOAS that Craig McClanahan talks about.
The thing is, I think Steve’s developers are right. They need some kind of “RESTful like interface”. I do agree that you don’t need a document that describes status codes. The status codes exchanged between a RESTful client and server for a given HTTP operation is well defined by the HTTP specification. Users should not try to override the meaning of a given status code. The thing is, even with links, you still need to document which relationships will be available, what they do, and what formats the linked URIs expect. As a client developer, you need to know this information ahead of time. For state-changing interactions, you also need to know whether you need to do a PUT or POST. This is extremely important information because PUT is idempotent and POST is not. For those URI’s that take query parameters, you will need to define what query parameters there are and what values they expect. Finally, on error status codes, you will need to know whether or not the server will return a representation that describes the error and what type it will be.
WADL allows you to define all this stuff. It allows you to define URIs, their media types, what methods they expose, what query parameters, what, if any representations are returned on failures. It also allows you to define links and how they relate to other resources.
<resource_type id="vdc"> <method name="GET"> <response status="200"> <representation mediaType="application/vnd.order+xml"> <parameter name="CANCEL" path="/order/link[@rel='CANCEL']" style="plain"> <link resource_type="cancel"/> </parameter> <parameter name="PAYMENT" path="/order/link[@rel='PAYMENT']" style="plain"> <link resource_type="payment"/> </parameter> </representation> </response> </method> </resource_type> <resource_type id="cancel"> <method name="PUT"> <failure status="400" mediaType="aplication/vnd.error+xml"/> </method> </resource_type> ...
I’ll admit, I am squeamish about WADL. One of the things I liked about REST is that I wasn’t stuck writing WSDL documents and being dependent on a bloated SOAP stack. WADL is just as verbose as WSDL. I like how you can have any link structure you want in your documents and map it using XPath or some JSON equivalent. Its just so damn verbose! I still think something like this encourages an RPC-like approach to system design. So what do we do instead? Since HATEOAS is so close to the dataformat, awhile back, I talked about using XML schema to define your interface and link relationships. Subbu also talks about expanding Atom links with a template, which should satisfy the query parameter problem. I would also suggest adding allow and failure-type attributes to Atom links. Allow being what HTTP methods are allowed, and failure-type specifying the media type that would be used with any failure responses. So, here would be an example:
<order id="123"> <amount>$123.45</amount> <atom:link rel="CANCEL" href="http://orders.com/orders/123/cancelled" allow="GET, PUT" failure-type="application/vnd.failures+xml"/> <atom:link rel="PAYMENT" href="http://orders.com/orders/123/payment" type="application/xml" allow="GET, PUT" failure-type="text/plain"/> ... </order>
I think this covers the bases. Thoughts? Viable?
May 21, 2009 @ 13:03:53
Hi Bill, are you aware of mnot’s link header draft? It offers a nice way for standardizing the rel part:
http://www.mnot.net/drafts/draft-nottingham-http-link-header-05.txt
May 21, 2009 @ 13:24:51
@Stefan:
Interesting, correct me if I’m wrong, but the RFC does not solve the issues I’ve presented here. Also, I don’t see how its that useful. I would much rather have a well-formed link structure specific to the format I’m transmitting (XML/JSON) than have to embed the suggested format within, lets say an attribute or element in XML and further reparse it.
May 21, 2009 @ 13:52:50
If you properly describe the media types you are using then you do not need WADL. All you need is the root url and the media type that url returns.
Imagine for a second that when building a RESTful interface you had a requirement that said all Urls must be just a GUID. i.e. http://example.org/0A29FF9E-7F9C-4437-8B11-F424491E3931
I find that once you remove the crutch of the descriptive url, how to document RESTful interfaces becomes clearer. I’m not saying descriptive urls are a bad thing, in fact I believe the structure of the Url is very important to the server. However, the client should not care what the url is.
May 21, 2009 @ 14:11:27
@Darrel
I agree to a degree. You don’t think that we need allow, and failure-type metadata within your links for update relationships?
May 21, 2009 @ 20:36:42
Sure, I put all sorts of meta data in my links. It is documented in the specification of my media type.
HTTP describes my verbs, my media types describe my nouns and the relationships between my nouns. What left is there for WADL to describe.
May 21, 2009 @ 14:40:42
I happen to have asked Marc Hadley (JAX-RS spec lead, author of the WADL spec) about how WADL might be used to describe a REST service driven by self-discovered embedded links, rather than by URI template patterns. His response was, basically, you could do this but need to establish a convention on how to figure out which elements are links. His full comments were on his blog:
http://weblogs.java.net/blog/mhadley/archive/2009/04/hateoas_with_wa.html
May 21, 2009 @ 16:00:42
Its not true that WADL ignores HATEOAS and links. See my recent blog entry for an example:
http://weblogs.java.net/blog/mhadley/archive/2009/04/hateoas_with_wa.html
May 21, 2009 @ 23:49:30
How about just a page with some examples of it in various permutations. I liked your idea of something “schema like” to describe the structured data when its not obvious. Really, its a human developer that will be gluing this together, code generators will only do so much (and poorly) so just make it friendly, humane.
May 27, 2009 @ 05:35:05
How about just a page with some examples of it in various permutations. I liked your idea of something "schema like" to describe the structured data when its not obvious. Really, its a human developer that will be gluing this together, code generators will only do so much (and poorly) so just make it friendly, humane.
Aug 04, 2009 @ 00:39:26
I’m sure various schema will emerge but it’s not something a REST architecture needs. The idea of opaque URIs seems to be a core value proposition of the architecture. REST separates the concerns of parsing URIs by making assuming they have no distinguishing characteristics.
GET and PUT are fine but what if we need to hop, skip and jump and if so how high or far, and what object are we presumably directing? The rich API accessible via RPC looks rather compelling to the average programmer at that point… until they look at JAX-RS.
So, JAX-RS makes it a breeze to implement the richness of behavior we are looking for by adding semantics to those otherwise meaningless URIs. Ad hoc interpretation works, but layering on some schema definition is fine, too. As long as it’s not confused with REST, no problem.
Jan 28, 2010 @ 09:58:26
I think that WADL helps to implement clients in a client-server architecture. I imagine writing Java client for the complex HATEOAS web service with lots of possible states… With WADL this step can be completely automated, though you won’t have some state constraints. Same is true about test cases and documentation – nowadays there exist quite a few generators utilizing WADL, you can find some examples here.
Also, WADL gives you a standard way to document your interfaces. For example, you can specify not only the representations, fault codes and so on, but also (links to) some business constraints affecting the behavior of your server (you can attach documentation to any element in WADL, so it will be easier for your users to find it).
Speaking about your schema idea… It seems to me that transferring all the information about the service (allowed methods, fault codes, etc) is a bad idea (at least, it’s an overhead). Instead, it is better to provide only an URL pointing at some definition, for example to WADL 🙂 Think of the schema itself – normally we don’t put its contents into every XML file, we use xsd:schemaLocation instead.
Reading List « function(arg)
Jun 28, 2013 @ 20:10:32