Exploring Hypermedia Support in Jersey
During the last few weeks, Marc H., Paul S. and myself have been exploring some ideas to support Hypermedia in Jersey. The outcome of this investigation is an experimental implementation that is available in Jersey's trunk (module version 1.2-SNAPSHOT). Exactly what it means to support hypermedia is still an area of research, and some other implementations of JAX-RS (notably RESTfulie) have also proposed APIs for it.
The REST architectural style, as defined by Roy Fielding in his thesis, is characterized by four constraints: (i) identification of resources (ii) manipulation of resources through representations (iii) self-descriptive messages and (iv) hypermedia as the engine of application state. It is constraint (iv), hypermedia as the engine of application state or HATEOAS for short, that is the least understood and the focus of our investigation.
It has been identified by other authors that there are actions that cannot be easily mapped to read or write operations on resources. These operations are inherently more complex and their details are rarely of interest to clients. In our work, we introduce the concept of action resources. An action resource is a sub-resource defined for the purpose of exposing workflow-related operations on parent resources. As sub-resources, action resources are identified by URIs that are relative to their parent. For instance, the following are examples of action resources:
for purchase order “1” identified by http://.../orders/1.
A set of action resources defines—via their link relationships—a contract with clients that has the potential to evolve over time depending on the application’s state. For instance, assuming purchase orders are only reviewed once, the review action will become unavailable and the pay action will become available after an order is reviewed.
The notion of action resources naturally leads to discussions about improved client APIs to support them. Given that action resources are identified by URIs, no additional API is really necessary, but the use of client-side proxies and method invocations to trigger these actions seems quite natural. Additionally, the use of client proxies introduces a level of indirection that enables better support for server evolution, i.e. the ability of a server’s contract to support certain changes without breaking existing clients.
The Jersey extensions that we implemented were influenced by the following (inter-related) requirements:
- HATEOAS: Support for actions and contextual action sets as first-class citizens.
- Ease of use: Annotation-driven model for both client APIs and server APIs.
- Server Evolution: Various degrees of client and server coupling, ranging from static contracts to contextual contracts.
Please refer to the Hypermedia Chapter in the User's Guide for more information. Note that the proposed API is still experimental and will possibly evolve in unforeseen (and incompatible) ways. Your feedback will be extremely valuable in shaping future versions of this API.