After attending Dan's talk on REST, I stayed in the same room and listened to Don Brown talk about Struts 2's support for building RESTful applications. Below are my notes from the event.
What is wrong with today's web applications? You're using a modern web framework and you've cleanly separated your presentation and business logic. The biggest problem in modern web applications is Confusing URLs.
A URL should be a resource indicator - not a method invocation. Often, web applications have little or no caching. People use GET to perform data manipulation and POST may or may not change state (especially with JSF). Another big issue with modern web frameworks is there's too many abstraction layers that hide HTTP headers and it's difficult to manipulate them.
Today's applications are "information silos". There's a lot of information in your applications, but it's all buried in HTML, JavaScript and CSS. There's no way to get this information out of your application unless you explicitly expose it.
The answer to many of these problem is REST. It's the Way of the Web. To solve the information silo problem, you can create a single interface that has multiple representation of the same resource. There's one URI for all types of resources - be it XML, JSON or HTML. How does this work w/o modifying the URL? You modify the URL's extension.
Struts 2 has a couple of plugins that make developing RESTful services easier. The first is the Codebehind plugin and the 2nd is the REST plugin. Don is doing a demo with the REST plugin and shows that there's no Struts configuration files needed (no struts.xml and no struts.properties). The only thing that's necessary is to specify an "actionPackages" init-param on the DispatcherFilter in web.xml. This activates the Codebehind plugin that uses conventions to determine the view template's path.
In Don's demo, he's creating an "OrdersController" that implements ModelDriven. After implementing a setId() method (to set the id from the request parameters), a getModel() method (to return the Order object) and implementing a show() method that returns HttpHeaders, Don starts up his server and shows that http://localhost:8080/order/5 returns an HTML page. Changing the URL to end in /5.json returns JSON, /5.xml returns XML.
public HttpHeaders create() {
service.save(order);
return new DefaultHttpHeaders("success").setLocationId(order.getId());
}
The Poster Plugin for Firefox is great when you're working with REST services. Don used this plugin to show us that it's possible to post to JSON and get back JSON results. His demo was impressive, especially the fact that there was no XML configuration required for Struts. I also like how the DefaultHttpHeaders class allows you to manipulate headers in a type-safe manner.
To use the REST plugin, you'll want to use Struts 2.1. If you're using Maven, all you need to depend on is struts-rest-plugin. The struts-codebehind-plugin (as well as struts-core) will be pulled in by transitive dependencies.
One disadvantage of REST vs. WS-* is you can't generate client code from a WSDL. You'll have to write your client by hand. However, one advantage of REST is there's already lots of clients - your browser, curl, etc.
The Struts REST Plugin hasn't been officially released, but hopefully will be in Struts 2.1.1. You can checkout the code from SVN using the URL below. The documentation is located here.
http://svn.apache.org/repos/asf/struts/struts2/trunk/plugins/rest
Great talk Don - and excellent work on the REST plugin for Struts. I can't wait to try it out.
This afternoon, I attended Dan Diephouse's talk on RESTful services. Below are my notes from his presentation.
Roy Fielding coined the term REST (REpresentative State Transfer) in a thesis. Everything is a resource and are addressable via URIs. Resources are self descriptive and manipulated with verbs via a uniform interface. We don't want keys - we want links! Resources are hypertext. Hypertext is just data with links to other resources. Data model refers to other application states via links. This is possible because of the uniform interface!
REST and HTTP
There's 5 main HTTP methods: GET, POST, PUT, DELETE and HEAD. Get is cacheable and safe (there's no side effects). POST is an unsafe operation and can't be repeated. HEAD is used to retrieve a resources metadata, without getting the method body.
To create a new resource, you use POST. The server will return an HTTP 201 (Created) with a Location header. After that, you'll do a PUT to the location and you'll get back an HTTP 200.
Another option is to have the client generate a unique id and PUT to it straight away - instead of doing the POST/PUT - where the POST generates the unique URL.
The biggest problem with REST is firewalls. Many firewalls don't allow PUT or DELETE. Google fixes this by adding a header that specifies a method override.
One of the constraints of REST is all communication is stateless. Session state is kept on the client. The client is responsible for transitioning to new states. States are represented by URIs. The advantage is this improves visibility, reliability and scalability. You don't need to replicate session state on your services in a cluster.
ETag header
Resources may return an ETag header when it is accessed. On subsequent retrieval of the resource, client sends this ETag header back. The client can then use a "If-None-Match" header with the ETag value to communicate with the server. The server will send back a 304 (Not Modified) with no body if nothing has changed. LastModified is a similar header that servers send back. The client will then send a "If-Modified-Since" header and get a similar result.
REST allows scalability through Caching - a.k.a. "cache the hell out of it". There's 3 types of cache:
How does caching actually work? A resource is eligible for caching if:
- The HTTP response headers don't say not to cache it
- The response is not authenticated or secure
- No ETag or LastModified header is present
- The cache representation is fresh
Is your cache fresh? Yes, if the expiry time has not been exceeded and the representation was LastModified a relatively long time ago. If it's stale, the remote server will be asked to grab a new copy of the resource and send it back to you.
HEAD allows you to get metadata about a resource without getting the resource itself. You can use it to test that a resource exists, that a link is valid or to check when a resource was last modified.
There's an "Expect 100 Continue" header you can use to query the server to see if it's capable of receiving a message. The nice thing about this is you get client-server communication before sending the message body. An example was provided where you upload an image from your cell phone. You don't want to start sending the message body if authentication is required. Your phone can check for "100 continue" to determine if it should start uploading the file.
For doing batch operations with REST, you can use HTTP connection pipelining. Unfortunately it's broken by some firewalls. Another option is to POST a whole set of data. GData (an extension to the Atom Publishing Protocol) fixes this by allowing you to post a whole bunch of entries at once. Unfortunately, this approach has received a very cold reception from the community.
The Atom Publishing Protocol is a RESTful protocol for building services. You can use it to create, edit, delete entries in a collection. It's an extensible protocol; examples include paging extensions, GData and OpenSearch.
Why should you use APP for your application? Because it provides ubiquitous elements which have meaning across all contexts. You can leverage existing solutions for security (HTTP Auth, WSEE, Google Login, XML Signatures and Encryption). It also eliminates the need for you to write much of the client/server code. Alternatives to APP include HTTPD, Java (Servlets, Restlets, Spring MVC), Ruby on Rails and many others.
Limitations of REST are HTTP is NOT an RPC or message passing system. It also isn't as secure as other solutions. A lot of times, folks just use SSL and basic authentication - which isn't the most secure system.
Dan posted his presentation on his blog if you'd like to download it.