Hypermedia REST API adapter
Enabling hypermedia REST at RentIT
We will start by updating RentIT’s REST adapter to integrate hypermedia controls in the resource representations (i.e. REST data transfer objects). To this end, we will focus in the life cycle of Purchase Orders and our goal is then to integrate hyperlinks in the resource representations to reflect the transitions on states. The following state model models the Purchase order life cycle.
Note that the state model differs from the assumptions made in the previous
practicals. The idea is to make explicit that the acceptance/rejection
of a purchase order by a RentIt’s clerk. Therefore, we will assume
that as part of the creation of the purchase order a plant reservation
is automatically started. If no plant inventory item is available the
purchase order is automatically reject. On the other hand, if the plant
reservation succeeds, the purchase order is set to the status pending confirmation
.
Later, a RentIt’s clerk will be responsible for deciding whether
to accept or reject a purchase order.
You must take this change into consideration and
update RentIt’s implementation accordingly. We will
now guide you through the major changes that we have to apply to RentIt’s
application.
We fist need to configure Spring hateoas to produce JSON HAL resource representations. This step is straight forward as we only have to annotate the entry class of our RentIt’s project, as shown below.
I recently found that, for the version of Spring boot that we using, we will have to add the following dependency:
It might be the case that the dependency above is not required in your project.
In order to implement the transitions in the state model, we first specify
the corresponding controller methods (at least an empty implementation
that will eventually replaced with the actual one). For instance, to
implement the transitions that are enabled at PENDING
state, we would need to add the following methods to PurchaseOrderRestController
.
The state machine is built inside the resource assembler. If we follow
with the example above, we can add the corresponding transitions in
PurchaseOrderAssembler
as follows:
Spring Hateoas provides some convenience methods (e.g. linkTo
and methodOn
) to build the links. With this methods we
build the URI template that would allow us to reach a method in the
controller. For instance, we would like to build the URI /api/sales/orders/{id}
and connect it to the method
PurchaseOrderRestController.acceptPurchaseOrder
. Accordingly,
we would use
linkTo(methodOn(PurchaseOrderController).acceptPurchaseOrder(dto.get_id()))
.
Internally, Spring Hateoas will analyze the set of annotations in the
controller class to create the corresponding URI template.
As mentioned before, HAL does not allow us to specify the HTTP verb to
be used with a given URI. That is why we have implemented a couple
of classes to add the additional information. You will find such classes
in the reference RentIT implementation that we have provided (the classes
are located in package
com.rentit.common.rest
and are called ExtendedLink
and ResourceSupport
). Take note that an extended link
must be created via its constructor as shown above. The constructor
requires a regular Spring Hateoas link, the name of the relation (e.g.
accept
) and the HTTP verb.
Very important, you must update all your DTOs to extend the class ResourceSupport
that is located in package com.rentit.common.rest
and
not the one provided by Spring Hateoas.
In order to use the convenience methods, you must include the following import statements (among others):
Testing Hypermedia in RentIT’s side
We will now modify our Controller tests in RentIt’s project to
check and exploit the presence of hyperlinks in the resource representations.
As pointed out before, Spring hateoas uses a separate object mapper
which has been tailer to render the hyperlinks. Do not forget to use such object mapper in your test code. The latter is done by adding the @Qualifier
annotation
to the code as shown below.
The test code above looks quite similar to what you should already have,
except for the last two lines. You can see that we now have the method
get_xlink()
to fetch the hyperlink associated with a given
relation. In the case above, we are checking that after creating the
purchase order (that is, when the purchase order PENDING
,
waiting for confirmation), the resource representation must include
a hyperlink associated with accept
. In the last line of
the test, we use such hyperlink to accept the purchase order.