# Hypermedia Actions

## Introduction

It is generally understood that, in order to follow the REST style, URIs should be assigned to anything of interest (resources) and a few, well-defined operations should be used to interact with these resources. For example, the state of a purchase order resource can be updated by POSTing or PATCHing a new value for the its state field. However, 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. For example, given a purchase order resource, the operation of setting its state to `REVIEWED` may involve a number of different steps such as:

1. checking the customer's credit status
2. reserving product inventory
3. verifying per-customer quantity limits.

Clearly, this workflow cannot be equated to simply updating a field on a resource. Moreover, clients are generally uninterested in the details behind these type of workflows, and in some cases computing the final state of a resource on the client side, as required for a PUT operation, is impractical or impossible.

We call these operations actions and, because they are of interest to us, we turn them into 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:

        http://.../orders/1/review
        http://.../orders/1/pay
        http://.../orders/1/ship

for purchase order "1" identified by `http://.../orders/1`.

Action resources as first-class citizens provide the necessary tools for developers to implement HATEOAS. 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.

## Hypermedia by Example

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. Finally, it has been argued that using client proxies is simply more natural for developers and less error prone as fewer URIs need to be constructed.

Rather than presenting all these extensions abstractly, we shall illustrate their use via an example. The complete example can found in hypermedia-action-sample. The Purchase Ordering System exemplifies a system in which customers can submit orders and where orders are guided by a workflow that includes states like `REVIEWED`, `PAYED` and `SHIPPED`. The system's model is comprised of 4 entities: `Order`, `Product`, `Customer` and `Address`. These model entities are controlled by 3 resource classes: `OrderResource`, `CustomerResource` and `ProductResource`. Addresses are sub-resources that are also controlled by `CustomerResource`. An order instance refers to a single customer, a single address (of that customer) and one or more products. The XML representation (or view) of a sample order is shown below.

        <order>
            <id>1</id>
            <customer>http://.../customers/21</customer>
            <shippingAddress>http://.../customers/21/address/1</shippingAddress>
            <orderItems>
                <product>http://.../products/3345</product>
                <quantity>1</quantity>
            </orderItems>
            <status>RECEIVED</status>
        </order>

Note the use of URIs to refer to each component of an order. This form of serialization by reference is supported in Jersey using JAXB beans and the `@XmlJavaTypeAdapter` annotation. An `XmlAdapter` is capable of mapping an object reference in the model to a URI. Refer to hypermedia-action-sample for more information on how this mapping is implemented.

## Server API

The server API introduces 3 new annotation types: `@Action`, `@ContextualActionSet` and `@HypermediaController`. The `@Action` annotation identifies a sub-resource as a named action. The `@ContextualActionSet` is used to support contextual contracts and must annotate a method that returns a set of action names. Finally, `@HypermediaController` marks a resource class as a hypermedia controller class: a class with one more methods annotated with `@Action` and at most one method annotated with `@ContextualActionSet`.

The following example illustrates the use of all these annotation types to define the `OrderResource` controller.

Several details about this class are omitted for clarity. The reader is referred to the hypermedia sample for more details.

        @Path("/orders/{id}")
        @HypermediaController(
            model=Order.class,
            linkType=LinkType.LINK_HEADERS)
        public class OrderResource {

            private Order order;

            ...

            @GET @Produces("application/xml")
            public Order getOrder(@PathParam("id") String id) {
                return order;
            }

            @POST @Action("review") @Path("review")
            public void review(@HeaderParam("notes") String notes) {
                ...
                order.setStatus(REVIEWED);
            }

            @POST @Action("pay") @Path("pay")
            public void pay(@QueryParam("newCardNumber") String newCardNumber) {
                ...
                order.setStatus(PAYED);
            }

            @PUT @Action("ship") @Path("ship")
            @Produces("application/xml")
            @Consumes("application/xml")
            public Order ship(Address newShippingAddress) {
                ...
                order.setStatus(SHIPPED);
                return order;
            }

            @POST @Action("cancel") @Path("cancel")
            public void cancel(@QueryParam("notes") String notes) {
                ...
                order.setStatus(CANCELED);
            }
        }

The `@HypermediaController` annotation above indicates that this resource class is a hypermedia controller for the `Order` class. Each method annotated with `@Action` defines a link relationship and associated action resource. These methods are also annotated with `@Path` to make a sub-resource. There does not appear to be a need to use `@Action` and `@Path` simultaneously, but without the latter some resource methods may become ambiguous. In the future, we hope to eliminate the use of `@Path` when `@Action` is present. The element `linkType` selects the way in which URIs corresponding to action resources are serialized: in this case, using link headers. These link headers become part of the an order's representation. For instance, an order in the `RECEIVED` state, i.e. an order that can only be reviewed or canceled, will be represented as follows.

        Link: <http://.../orders/1/review>;rel=review;op=POST
        Link: <http://.../orders/1/cancel>;rel=cancel;op=POST
        <order>
            <id>1</id>
            <customer>http://.../customers/21</customer>
            <shippingAddress>http://.../customers/21/address/1</shippingAddress>
            <orderItems>
                <product>http://.../products/3345</product>
                <quantity>1</quantity>
            </orderItems>
            <status>RECEIVED</status>
        </order>

Without a method annotated with `@ContextualActionSet`, all actions are available at all times regardless of the state of an order. The following method can be provided to define a contextual contract for this resource.

        @ContextualActionSet
        public Set<String> getContextualActionSet() {
            Set<String> result = new HashSet<String>();
            switch (order.getStatus()) {
                case RECEIVED:
                    result.add("review");
                    result.add("cancel");
                    break;
                case REVIEWED:
                    result.add("pay");
                    result.add("cancel");
                    break;
                case PAYED:
                    result.add("ship");
                    break;
                case CANCELED:
                case SHIPPED:
                    break;
            }
            return result;
        }

This method returns a set of action names based on the order's internal state; the values returned in this set correspond to the `@Action` annotations in the controller. For example, this contextual contract prevents shipping an order that has not been payed by only including the `ship` action in the `PAYED` state.

## Client API

Although action resources can be accessed using traditional APIs for REST, including Jersey's client API, the use of client-side proxies and method invocations to trigger these actions seems quite natural. As we shall see, the use of client proxies also introduces a level of indirection that enables better support for server evolution, permitting the definition of contracts with various degrees of coupling.

Client proxies are created based on hypermedia controller interfaces. Hypermedia controller interfaces are Java interfaces annotated by `@HypermediaController` that, akin to the server side API, specify the name of a model class and the type of serialization to use for action resource URIs. The client-side model class should be based on the representation returned by the server; in particular, in our example the client-side model for an `Order` uses instances of `URI` to link an order to a customer, an address and a list of products.

        @HypermediaController(
            model=Order.class,
            linkType=LinkType.LINK_HEADERS)
        public interface OrderController {

            public Order getModel();

            @Action("review")
            public void review(@Name("notes") String notes);

            @POST @Action("pay")
            public void pay(@QueryParam("newCardNumber") String newCardNumber);

            @Action("ship")
            public Order ship(Address newShippingAddress);

            @Action("cancel")
            public void cancel(@Name("notes") String notes);
        }

The `@Action` annotation associates an interface method with a link relation and hence an action resource on the server. Thus, invoking a method on the generated proxy results in an interaction with the corresponding action resource. The way in which the method invocation is mapped to an HTTP request depends on the additional annotations specified in the interface. For instance, the `pay` action in the example above indicates that it must use a `POST` and that the `String` parameter `newCardNumber` must be passed as a query parameter. This is an example of a static contract in which the client has built-in knowledge of the way in which an action is defined by the server.

In contrast, the `review` action only provides a name for its parameter using the `@Name` annotation. This is an example of a dynamic contract in which the client is only coupled to the `review` link relation and the knowledge that this relation requires `notes` to be supplied. The exact interaction with the `review` action must therefore be discovered dynamically and the `notes` parameter mapped accordingly. The Jersey client runtime uses WADL fragments that describe action resources to map these method calls into HTTP requests.

The following sample shows how to use `OrderController` to generate a proxy to review, pay and ship an order. For the sake of the example, we assume the customer that submitted the order has been suspended and needs to be activated before the order is reviewed. For that purpose, the client code retrieves the customer URI from the order's model and obtains an instance of `CustomerController`.

`CustomerController` is a hypermedia controller interface akin to `OrderController` which is omitted since it does not highlight any additional feature.

        // Instantiate Jersey's Client class
        Client client = new Client();

        // Create proxy for order and retrieve model
        OrderController orderCtrl = client.view(
            "http://.../orders/1", OrderController.class);

        // Create proxy for customer in order 1
        CustomerController customerCtrl = client.view(
            orderCtrl.getModel().getCustomer(),
            CustomerController.class);

        // Activate customer in order 1
        customerCtrl.activate();

        // Review and pay order
        orderCtrl.review("approve");
        orderCtrl.pay("123456789");

        // Ship order
        Address newAddress = getNewAddress();
        orderCtrl.ship(newAddress);

The client runtime will automatically update the action set throughout a conversation: for example, even though the `review` action does not produce a result, the HTTP response to that action still includes a list of link headers defining the contextual action set, which in this case will consist of the `pay` and `cancel` actions but not the `ship` action. An attempt to interact with any action not in the contextual action set will result in a client-side exception if using proxies (as shown above), or a server-side exception if using some other API.

The following annotations are allowed in hypermedia controller interfaces: `@Name`, `@Consumes`, `@Produces`, `@CookieParam`, `@FormParam`, `@HeaderParam`, `@QueryParam`, as well as any HTTP method annotation like `@POST`, `@PUT`, etc. All other annotations not listed here are unsupported at this time (of note, `@MatrixParam` is not supported). The `@Name` annotation used in Jersey is defined in `com.sun.jersey.core.hypermedia`.

## Server Evolution

In the last section, we have seen how the use of client proxies based on partially annotated interfaces facilitates server evolution. An interface method annotated with `@Action` and `@Name` represents a loosely-coupled contract with a server. Changes to action resource URIs, HTTP methods and parameter types on the server will not require a client re-spin. Naturally, as in all client-server architectures, it is always possible to break backward compatibility, but the ability to support more dynamic contracts --usually at the cost of additional processing time-- is still an area of investigation.

We see this form of hypermedia support in Jersey as a small step in this direction, showing the potential of using dynamic meta-data for the definition of these type of contracts. The use of dynamic meta-data requires the server to return WADL fragments when using `OPTIONS` on an action resource URI. When dynamic meta-data is not available (for example if using an older version of Jersey on the server) client interfaces should be fully annotated and a tighly-coupled contract should be used instead.

## Configuring Hypermedia in Jersey

There are a few configuration options in hypermedia-action-sample that are worth highlighting. First, a special filter factory `HypermediaFilterFactory` must be enabled. This can be done programmatically by adding

    com.sun.jersey.server.hypermedia.filter.HypermediaFilterFactory

to the list defined by

    com.sun.jersey.spi.container.ResourceFilters

or declaratively in the application's `web.xml` file. Refer to the Java class `com.sun.jersey.samples.hypermedia.Main` in the hypermedia sample for an example of how to do this using Grizzly (which can be executed with `mvn install exec:java`). Second, hypermedia applications must included the following Maven runtime dependencies:

            <dependency>
                <groupId>com.sun.jersey.experimental.hypermedia-action</groupId>
                <artifactId>hypermedia-action-server</artifactId>
                <version>${jersey-version}</version>
            </dependency>
            <dependency>
                <groupId>com.sun.jersey.experimental.hypermedia-action</groupId>
                <artifactId>hypermedia-action-client</artifactId>
                <version>${jersey-version}</version>
            </dependency>

Last, even though the annotation `@HypermediaController` has a `linkType` element, only the `LinkType.LINK_HEADERS` option is currently supported and must be used by both clients and servers.