RESTful Web Applications with Subbu Allamaraju
Subbu works at Yahoo! developing standards, patterns and practices for HTTP web languages. In the past, he was a web service and Java developer. He was also a standards contributor at BEA and an author of books on Java EE. His current passion is HTTP and REST. Subbu confesses that he's not a web developer, has no interest in the internals of programming models used for web frameworks and he's only interested in the visible aspects of the architecture.
"The Web is Mostly Restful"
Being RESTful in an abstract sense means:
- Resources are named by URIs
- Resources have representations (Atom, HTML, JSON, XML)
- Resources contain contextual links to allow navigation of state
- There's a Uniform Interface
In the web today, some resources and URIs are personalized, but most are not. Some depend on sessions, but most do not. The consequence of a personalized UI with a non-unique URI is you cannot rely on browser caching.
The web is full of different representations (HTML, XML, JS, PDF, CSS, Flash). The problem with HTML is you can't tell links that you want a particular representation based of a link. The links are hard-coded to be a particular content-type. However, some media types on responses are ignored. This is often a problem with browsers and whether the user has plugins installed.
The Uniform Interface for the web is HTML and primarily links and forms (GET and POST). There's still some misconceptions (e.g. POST is secure). However, it's not about security, it's about idempotency and safety. You need to make sure you only use POST when you're changing data. POSTs are not repeatable. GET URIs are not always refreshable, which is quite unfortunate. Users shouldn't have to fight the back button.
Caching is a fundamental aspect of the web. Even in a personalized site, most of the content can be cached. The web is read-only for the most part. However, many enterprise web applications don't take advantage of caching. This is fine when there's not that many users, but it's bad when you want to scale to thousands of users. There's several frameworks that use cache-busting and prefer backend caching over HTTP caching. These frameworks are not using the web like they should.
Backend caching (e.g. Memcached) uses a non-uniform interface and you need to explicitly program to it. Frontend/HTTP caching has a uniform interface that's pluggable. Backend caching is generally more expensive to develop and deploy. There are cases where data should be cached on the backend, but you shouldn't focus all on backend caching w/o doing some frontend caching.
With Ajax, you get more opportunities to be RESTful. XMLHttpRequest is another HTTP client that can be programmed to. It has full support for the uniform interface, which allows content negotiation, optimistic concurrency and caching. Cross-domain hacks can be done with <script> and <iframe> to tunnel requests over GET. The W3C has been working for the last two years on how to do cross-domain Ajax w/o using hacks. The problem with current cross-domain implementations is they often use GET for everything, which isn't very RESTful. Subbu recommends using a proxy on the same domain if you do need to talk to other domains. This will allow your Ajax code to remain RESTful.
Web Frameworks
Web development is hard because of all the moving pieces that exist. Because of this, many web frameworks have been created to solve the various problems. In 1997, there were servlets. They provided basic plumbing and closely reflected HTTP/1.1. Servlets provided a poor programming model, but it allowed a lot of frameworks to be built on top of it. We don't use servlets to write applications, only to write application frameworks. The second era came about in 2001 when Action-oriented frameworks became popular. In 2004, JSF and friends came to play. JSF is a component-based framework with known limitations (complex, slow, uses POST for almost everything, Ajax is difficult). These limitations have resulted in a number of third-party patches being developed to solve these issues.
JSF was designed to use the request to create a component tree that maintains state. Unfortunately, the state is not something the developer has control over. It's not the state of the application, it's the state of the components. The client's knowledge of the state is mentioned with a cookie and the server keeps the state in the session. The problem with JSF is you don't have a choice of state in your application - you can't write stateless applications like you can with servlets.
JSF uses overloaded URIs for its resources. When you have one URI with multiple representations, there's no way to tell how a representation was chosen. JSF's compromise is to allow client-side state saving. However, they do this by putting hidden field in the form and requiring POST for navigation.
JSF vs. REST
Basically, these two are at opposite extremes. JSF is focused heavily on a UI component model. The people that developed it misinterpreted how the web works and made some fundamental questionable choices. You can patch it, but you can not fix it.
Web 2.0 Frameworks
GWT is a cross-compilation based framework. You write Java to generate JavaScript (b/c everyone hates writing JavaScript). It mashes client and server code into a single source. These layers communicate using GWT-RPC. Typical RPC concerns do not apply since code generation handles coupling and the client is downloaded from the same application. GWT-PRC does POSTs to the server and uses HTTP like a transport layer. To be fair, GWT does allow you to use a RequestBuilder to use the web like it should be used.
This class allows more control over HTTP requests, it supports GET and POST and it allows so-called RESTful layers (GWT-REST and GET-Restlet). GWT is focused heavily on ease-of-use, which is good. It's modeled after RPC and breaks the uniform interface and focuses on backend caching. Unlike JSF, GWT is fixable, but the community tends to use RPC instead of RequestBuilder.
SOFEA has a central promise of SOA. Business logic is a reusable service that changes less often. The presentation application calls those services and changes more often. The nice thing about this type of architecture is it allows a separation of concerns and loose coupling. However, it doesn't embrace REST like it should. Appcelerator is an implementation of SOFEA that has a Ruby on Rails-like usability. However, it uses a SOAP/HTTP style with messaging and POSTs to a single URI. Appcelerator is interesting, but it introduces a different style of coupling. It breaks URI opacity and client deals with POX instead of links.
Conclusion
Don't fight the architecture of the web. Innovate and enhance instead of breaking. If nothing else, break judiciously. As developers, we should demand more from our frameworks and make sure they use the web and HTTP like it should be used.
Matt,
What you think about Spring 3.0 in terms of RESTful'ality?
Posted by Diego Plentz on October 24, 2008 at 04:36 PM MDT #
I haven't come to the conclusion that JSF is not fixable yet. It looks like there are some major overhauls going on related to state saving and RESTful URLs in JSF 2.0. Plus they're building in the best pieces from those addons. Like GWT, JSF 2.0 is focused heavily on ease of use.
It seems that many people have made up their minds about JSF already and only talk about what it was without acknowledging what it will soon be. How closely do you follow the JSF 2.0 issue tracker, blogs, spec, etc?
Posted by Ryan on October 24, 2008 at 05:11 PM MDT #
Posted by Renat Zubairov on October 24, 2008 at 05:33 PM MDT #
Posted by Claudio on October 24, 2008 at 07:12 PM MDT #
"It seems that many people have made up their minds about JSF already and only talk about what it was without acknowledging what it will soon be."
Interesting argument. But it's hard to be non-critical about a spec that got things so wrong - not just REST, but basic HTTP usage. A JSF that supports REST is going to be a complete overhaul, no? And what made the sepc writers change their minds? That's the question i like to ask of anyone who seems to have suddenly "got" the web.
Posted by Bill de hÓra on October 25, 2008 at 12:48 AM MDT #
I don't think you'll find JSF expert group members who will agree that they got it fundamentally wrong. They will tell you about how they only had so much time to design a new web framework and chose to focus on making sure it was extensible because they knew they didn't have enough time to fully complete it. After the spec was released many of them continued working on it by trying out new ideas (Shale, JSFTemplating, Facelets, Ajax4JSF, DynaFaces, etc). and this time around they get to unify the best ideas.
Have a look at some tickets that show that they acknowledge issues in the current state saving implementation, and mention "Mostly stateless" state saving:
https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=272
https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=139
Here's a ticket about overhauling UIData:
https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=236
Integration with JAX-RS:
https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=486
HTTP GET support:
https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=146
Have a look at this page that shows examples of how some simple elements in faces-config.xml could enable support for HTTP GET parameters and URL rewriting for RESTful URLs:
http://www.jtict.com/blog/seam-form-url-rewriting
I don't think the HTTP GET/url rewriting is in JSF 2.0 early draft yet. When I asked they said they will be working on this feature shortly.
Posted by Ryan on October 25, 2008 at 01:53 AM MDT #
"Unlike JSF, GWT is fixable, but the community tends to use RPC instead of RequestBuilder."
Well the reason for that is, that GWT-RPC is incredibly fast and is easy to integrate with existing Spring-backends, even with Java 5 languages features.
Serialization and Parsing is just done for you. No need to parse XML/JSON on the client when using direct GWT-RPC (Plain Old Java Interfaces) instead of RequestBuilder.
But still it is possible to use it, like seen here: http://www.gwtphp.com
Posted by Sakuraba on October 25, 2008 at 02:31 PM MDT #
Posted by William Hogan on October 25, 2008 at 10:18 PM MDT #
There's too much preaching here for my taste.
If backend caching is so bad, why is it so popular? I don't think it's ignorance or stupidity; I think it's a bus that is taking the developers in the direction they want to go, or else it is under their control when front-end caching is not.
Posted by Peter B on October 26, 2008 at 01:25 PM MDT #
Matt - thanks for the write up.
The slides are at http://www.subbu.org/blog/2008/10/slides-from-the-colorado-software-summit
Posted by Subbu Allamaraju on October 27, 2008 at 03:35 AM MDT #
Sakuraba - the point about GWT-RPC is that it chose an RPC mechanism between the client-side code and the server-side code. This forced them to use POST for everything, thus defeating the uniform interface. Consequently, their answer for caching (as found in one of the emails in the GWT googlegroup) is to use backend (i.e application specific) caching.
GWT is fixable by restricting the function calls to the uniform interface, e.g. as in
as each of these methods could be translated into respective HTTP verbs. Instead, since GWT lets you use non-uniform methods such as "doSomething" it has to marshal everything over POST.
Posted by Subbu Allamaraju on October 27, 2008 at 04:29 AM MDT #
Posted by Peter Svensson on October 28, 2008 at 08:54 AM MDT #
Posted by Claudio on October 28, 2008 at 09:04 AM MDT #
@Claudio: I posted my comments on the SOFEA arch at Comments on SOFEA at the google group on SOFEA.
Posted by Subbu Allamaraju on October 28, 2008 at 05:55 PM MDT #
@Ryan: "I don't think the HTTP GET/url rewriting is in JSF 2.0 early draft yet. When I asked they said they will be working on this feature shortly." I'll believe it when I see it. While it may be too early to say that JSF can't be fixed, I do think it's fair to say that a 1.0 spec based on such fundamental flaws is going to require a lot of work to get overhauled for a 2.0 release. It remains to be seen whether the JSF team will actually be able to deliver on those promises.
With that said, early drafts are pretty much worthless for my daily work. I'm only interested in what's currently ready for production use, which means JSF 1. From that perspective (i.e., when you limit the discussion to only what's actually been release, and not the vague, unfulfilled promises for a future release) JSF is not fixable. You can pile on Seam, Spring JSF, Web Flow, and other third party libraries, but it's still putting lipstick on a pig.
Posted by Kyle Adams on October 31, 2008 at 03:29 PM MDT #
Which frameworks to you have in your toolbelt? Do you favor one component oriented framework and one action framework, or do you prefer action frameworks for everything?
This is not a question for Matt Raible since I already know he learns them all.
Posted by Ryan on October 31, 2008 at 04:22 PM MDT #