An Attempt At a REST Programming Model
May 22nd, 2006I spent some time on the way home from JavaOne thinking about a REST programming model. The benefit of a REST programming model would be that it would give us an easy way to expose resources from POJOs and interfaces. I’ve started a wiki page to get some discussions going, but let me summarize/explain some ideas here.
A REST programming model would:
- Embrace the fundamental principles of REST
- Expose resources from Java
- Specify how to bind POST data/queries/path info to objects
- Specify a way to map URIs to objects/resources.
So lets take a look at the CustomerService I outlined:
public class CustomerService { @RestMethod(methods={HttpMethod.GET}) Customer getCustomer(@Path(index=2) String id); @RestMethod(methods={HttpMethod.DELETE}) void deleteCustomer(@Path(index=2) String id); @RestMethod(methods={HttpMethod.POST}) @WebResult(name=“customerId”) String addCustomer(Customer customer); @RestMethod(method={HttpMethod.PUT}) void updateCustomer(Customer customer); }
Lets break this down a little bit:
- @RestMethod specifies that a particular method on a class should be bound to an HTTP method - i.e. GET, PUT, POST, DELETE. An addCustomer method would bind to POST because we’d be submitting a chunk of XML.
- @Path(2) would mean - take parameter 2 from the URI and pass it as the customer id. For instance with a URI of “/customer/123″ the customer id would be “123″.
- @WebResult is an annotation from JAX-WS which we could use to specify the name of the response XML.
Data Binding
Our service would want to receive data from a number of places. The framework could help take care of this stuff magically:
- URI Path Info
- @Path(2) - would select the first query parameter - i.e. “123″ in “/customer/123″
- @QueryParameter(”customerId”) - would select the query parameter with the name “customerId”. Example: http://localhost/customer?customerId=123
- @RegexPath(”someregexexpression”) - would select some stuff from the uri via a regular expression.
- HTTP Headers. @HttpHeader(”customerId”) - could select the HTTP header with the name “customerId”
- XML in a POST/PUT method: This can be done with JAXB, XMLBeans, etc.
- Other stuff: The framework could be extended to work with anything - it could serve JPEGs, JSPs, spreadsheets, etc.
URI Mapping
Figuring out how to map methods to URIs seems like the trickiest part to me. There seem to be two basic ways to do it - inside the class or outside.
Inside the class you might use some kind of pattern matching annotation on the method like @Path(uri=”/customer/*”). Or you could do it at the class level - @RestService(uri=”/customer/*”).
Additionally there should probably be some type of way to map a class to URIs outside the class. For example:
CustomerService customerService = ...; ServiceRegistry registry = ...; registry.register(“/internal-customers/*”, customerService); registry.register(“/external-customers/*”, anotherCustomerService);
REST and SOAP/WSDL
I did take a look at the WSDL GET/POST delete bindings, but it seems these fall far short of what REST is about. What happened to PUT and DELETE?
REST is very different from the WSDL model. REST doesn’t think in terms of operations, which is probably what makes writing a description language for it hard.
Join in…
What do others think should go into a REST programming model? Feel free to chime in on the wiki with your ideas and thoughts! Its in the XFire wiki right now, but that doesn’t mean that this has to be an XFire only thing - there is no reason things like Spring MVC couldn’t support this as well.
Also I must acknowledge James Strachan’s influence on these thoughts above - he provided some good feedback late last night and also was the one who suggested getting things in a wiki for everyone.
Update: Guillaume Nodet reminds me I haven’t looked at the WSDL 2.0 REST binding. It looks like it may provide an OK way to turn URIs into parameters. I will have to take a more in depth look and post some comments later.