REST Litmus Test for Web Frameworks
I recently thought about what to expect in a web framework that claims to have "REST support", and came up with a list of questions that one should ask to see whether such a claim is justified:
- Does the framework respect that an HTTP message does not only consist of a URI? I.e., is dispatch done at least based on the HTTP verb, the URI, the Content-type and Accept headers?
- Can I easily use the same business logic while returning different content types in the response?
- Is there support for checking for conditional requests?
- Are ETags calculated automatically if none are set by the backend logic?
- Can I (as a framework user) easily read all HTTP request headers?
- Can I easily set all HTTP response headers?
- Can I use custom HTTP verbs?
- Is it obvious and easy how to return correct status codes with responses, and does the framework use them correctly (if it does so at all)?
Update: Two aspects added due to feedback by Erik Mogensen and Mike Amundsen:
- Is there an easy way to produce links that "point back" resources identified by whatever means the framework exposes (such as some form of routing)?
- Are resources identified and requests dispatched to code by the full URI, or is there an artificial distinction between the path and query parameters?
Along the same lines, here are some questions where a "Yes" indicates that a framework doesn't do things the way they're supposed to be done:
- Are GET, POST and other requests to the same URI dispatched to the same business logic by default?
- Am I required to use "extensions" (e.g. ".xml", ".json") to get different representations of the same resource? (Supporting this optionally is OK.)
- Are there method names in the URI?
Finally, I wonder whether there's any justification for a web framework to support "REST services" as an addition instead of the default, but I'm reluctant to put this into the second list.
Suggestions for extending the list are welcome.
For the “you are doing it wrong” item of requiring ‘extensions’ for content negotiations, there is a dependency on using Content-Type response headers in caching clients and proxies that can make using the same URI for different media types fragile. It’s easy for clients and proxies to do caching wrong and this would silently fail so I normally avoid relying solely on Accept headers for content negotiation.
Are we guaranteed to enter the REST paradise and have 70 custom verbs to play with if we follow this list?
@Anonymous, I have a certain feeling I know who you are, and I think I usually don’t discuss anything with you anymore. But to address the point: Obviously no, and I can’t see where I suggested anything like that. The fact that verbs are restricted to a set that’s shared by all resources is part of the architecture. That doesn’t mean it shouldn’t be possible to add something that becomes standardized, either in a closed group or publicly (such as PATCH recently did).
Stefan, it seems you left out hypermedia. How about calling this a litmus test of HTTP support in a framework. Adding a rule like Does the framework make it easy to map URIs to resources and back, to allow clients do discover resources through embedded links would fit nicely in your list.
Excellent suggestion, I’ll incorporate it.
Stefan, that was just a joke (a bad one obviously, since I have to explain) about how, to my taste, religious this whole REST thing has become. I intended no offense at all, really sorry if I caused any.
This looks to me like a very good list. Having looked for a good RESTful framework w/o much luck, I’ve ended up using a small PHP framework (really just a dispacher + orm that I use in conjunction w/ Smarty Templates). I do think the framework space is converging somewhat, with the trend being towards a more RESTful approach. I’ve come to think that a successful approach needs the following two characteristics:
1. URL mapping should point towards a “resource” NOT a representation 2. Controller logic (either a function or a method on a controller object) should be easy to write based on three pieces of information: HTTP Method, resource, and Format (I’d leave open the possibility to look at extension in conjunction w/ Accept-headers due to poor browser Accept-header implementations).
So a mapping would look like { “items”:”items”,”item/{id}”:”item” } for which we might have these methods: getItemsHtml,getItemsJson,getItemsAtom,postToItemsAtom,getItemHtml,getItemJson,putItemAtom,deleteItem, etc.
—peter keane
@Peter, agreed, with one minor addition: I prefer frameworks that can separate logic from format a little more. In your example, the methods would then be getItems, postToItems, putItem, deleteItem with some sort of separate reader/renderer framework for the formats.
Looks a bit minimalistic to me… But REST is minimalistic which is its strength. So I would think that this test defines what is REST, but it does not define a good framework. Maybe something for a next Litmus Test?
Christopher
@Christopher: I agree it’s minimalistic; the intent was to come up with a list of what a framework must offer. Good idea regarding a next post.
@Mike: good point. I’m not quite sure if I really want to compensate lacks of functionality or configuration in intermediaries by bending my application design. I’ve seen this in the “linked data” world (http://www4.wiwiss.fu-berlin.de/bizer/pub/LinkedDataTutorial/#Terminology) and I’m still not sure if I like that or not (because this is a strict instruction and I can’t decide this for myself). I would suggest to add the point “Support for the ‘vary’ header” (http://www.subbu.org/blog/2007/12/vary-header-for-restful-applications) to the list. IMO the “vary”, “accepts”, … usage depends on my system traffic. Not only because of clients / proxies doing it wrong but also because of the inefficiency of considering the “vary: accept” or “vary: *” header correctly, I would always try to limit the usage of this in heavy load scenarios. But on smaller applications this is a really nice feature which I don’t want to miss.
I would even broaden Peter’s additional point “1. URL mapping should point towards a “resource” NOT a representation” and state that it is essential for such a REST framework that at its heart it is built around the concept of resources.
This isn’t only important for the dispatching, but also for the backend storage to directly support the hierarchical nature of web URLs. A counter-productive example are “typical” systems that map URLs onto Objects that map via OCM frameworks onto relational models, unnecessarily complicating things for the REST developer. A native hierarchical storage model is quite helpful here, for most cases.
@Alex, while I prefer frameworks that work the way you describe, I don’t think it’s fair to say that’s an essential aspect. As long as the framework doesn’t actively push you into violating REST, I consider it perfectly fine to provide a low-level mechanism to dispatch based on the request message<.
As an aside, I don’t consider the “hierarchical nature” as a key aspect of RESTful HTTP.
@Stefan: Right, if you just look at the API side of the RESTful server, the implementation can be completely open.
Regarding hierarchy: I agree that if you design a different RESTful system, the identifiers could be built on some other structure, but for an HTTP/HTML based system, URLs as we know them are naturally following a hierarchical structure. When mapping domain models onto REST APIs, you come up with hierarchical resources, so why not support it directly? It’s not required in theory, but in practice it makes a huge difference. Because if you require some other mapping, the necessary conceptual thinking is more difficult for developers and it makes it “easier” for them to build interfaces that are not RESTful in my experience.
We agree in terms of what’s actually useful and should be supported, I just wanted to focus on the stuff that’s more or less rooted in the core REST theory.
i was thinking about the same thing a while ago and posted my thoughts about “REST Programming Toolbox Requirements” at http://dret.typepad.com/dretblog/2009/05/rest-programming-toolbox-requirements.html ; my thoughts were a little broader and did not include some of the details you have listed. maybe at some point it would be nice to combine/consolidate these requirements and come up with a more detailed list of what should be supported and how, and what’s required for server-side frameworks and what for client-side (and whether this distinction in itself is not a good idea because ideally, RESTful clients should expose their service anyway).
Hi Erik, I knew about your (excellent) post but it’s more of a wishlist of what libraries should support as opposed to what they have to (which doesn’t make it any less useful though). Whether things such as support for Atom and AtomPub have to be part of the core library is a design choice IMO.
Hello Stefan!
I think thats great guideline… I tried answering those questions regarding Restfulie, and I just suffer with the custom http verbs. Unfortunately (ruby version) Rails depends on Rack or its own list of supported methods. So we need to add a little monkey patch to allow it support custom verbs.
I really liked the “are there method names in the URI?” question. It easily describes most of the typical service mindset that we bring to rest when start trying to create an architecture based on it.
I prefer giving access to the response body instead of trying to unmarshal representations by default, what do you think about that?
Regards
Hi Guilherme, good points. Raw access to the body, as well as support for streaming, chunked and range requests should probably be a mandatory aspect, too.
This is a good list. However, I wonder whether two of those points on the second list are really as negative as you make them sound.
Routing GET, POST and other requests to the same logic. If you move outside of the ‘nice to have’ REST world into the real world you end up dealing with clients that sometimes only have limited capabilities. Browsers, client libraries that cannot generate PUT messages, etc. In that case, you may consider a design where for example POST or PUT of a single entity to a collection resource URI need to be interpreted as creation of a new entity, while POST or PUT of a single entity to a single entity URI need to be interpreted as update of that entity. In RESTx we explicitly deal with those clients. Furthermore, consider that there may be more than one way to express routing of specific methods to particular parts of the logic. In the end, you as the developer need to set this up. Whether you set this up with some annotation before the function name, with a routing configuration file, or whether you deal with it explicitly in code. So, the routing may be done before you reach a specific function, or the routing may be done explicitly by you after you reach a handling function, in the end it is still handled and dealt with differently.
Method names in the URI. Sure, I get that. ‘calculateAverage’ would be bad. However, in RESTx we use methods to specify sub-resources we deal with, not particular pieces of ‘do this’ functionality. For example, if you set up a RESTful resource to proxy a Twitter account then ‘status’ is one sub-resource of the ‘MyTwitterAccount’ resource. You can GET the status, or you can POST an update to it. But ‘timeline’ is also a sub-resource. In RESTx, ‘status’ and ‘timeline’ are actual method names, which do whatever is necessary to produce and/or deal with this sub-resource. But again: They denote sub-resources, not actions. I believe that this is ok and RESTful, while method names that denote actions are not. Not all resource have this natural idea of sub-resources, but most of them actually do. And in that case, expressing those with explicit functions tends to be a very natural and straight forward way to deal with them.
Another thing that occurred to me is that both client and server side need to be able to handle and expose all variants of absolute and relative URIs.
In other words, if a client wants to link together two resources, it would embed a link to another resource. It should be possible to do so using absolute or relative URIs: it should be able to use “../../foo/widget” or “/bar/foo/widget” or “http://www.example.org/bar/foo/widget” to achieve the same results using the RFC for URIs. The same could be said for the server side emitting links; some media formats may prefer absoluteness (e.g. a PDF representation) (for portability), while some server admins may prefer as relative as possible links (e.g. a HTML representation) (also for portability).
The code emitting links should in any case be coded to emit links to a resource and the representation in question should then use some preference on the relative—absolute scale
@mogsie, that’s an excellent point which has caused me quite a bit of pain in the past – and I’m not aware of any framework that does a good job of this.
@mogsie @Stefan: Apache Sling provides a map() method that maps internal resource paths back to public URLs. The configuration used is the same as for internal redirects, aliases etc. that allow the mapping of incoming request URLs to internal resources. This mapping config is open for the admin.
Great list Stefan! I’m planning to put together a news item on this @ infoQ, that way more people can weigh in on the criteria. Its a very concise yet interesting post so with your permission, i’d like to lift quite some chunks from your post.
One thing however, I find the criteria can get very inclusive; in terms of opinion. To be useful for an IT person/decision maker to check-off a list for an RFP, it might be a good idea to categorize the criteria into
Awesome list Stefan! Now the only other awesome thing missing is a short list of frameworks that pass this test. Based only on my memory (which is really bad) I couldn’t list more than a couple.
The best REST framework I’ve found is Webmachine: http://webmachine.basho.com/
I agree it’s very good (although maybe you should disclose you’re one of Basho’s employees ;-) )
Is there a REST discussion forum somewhere ? I am trying to wrap my head around metadata initiatives like Dublin Core etc. and how they relate to REST.
Hi Mohan, the best discussion group I’m aware of is the Yahoo! rest-discuss list.
My features list would include: