Monday 19 October 2015

A short list of Banking APIs

Banking APIs



There are an increasing number of APIs acting as hubs or aggregators for Banking services such as account data.  Let's take a quick look at each here (please contact me to add any @aphethean on Twitter):


Open Bank Project (https://www.openbankproject.com/)

Overview:  Designed to be a banking API enabler by hosting the hub across many banks or API deployed directly on top of a specific bank. 
Technology:  a REST-like API that does not make use of essentials such as hypermedia, content type negotiation, or link relations
Functional:  Retail banking services such as account, transactions, and payments
License model:  Open source, subscription hosting, or fee+maintenance


FIGO (http://figo.io/en/)

Overview:  Designed to be a banking api enabler by hosting the hub across many banks. 
Technology:  a REST-like API that does not make use of essentials such as hypermedia, content type negotiation, or link relations
Functional:  Retail banking services such as account, transactions, and payments
License model:  Rate limited / per request.


Yodlee (http://www.yodlee.com/)

Overview:  Transaction data aggregator; hosting the hub across many banks. 
Technology:  a REST-like API that does not make use of essentials such as hypermedia, content type negotiation, or link relations
Functional:  Retail banking services such as accounts and transaction data.
License model:  Rate limited / per request.


Kontomatik (http://kontomatik.com/)

Overview:  Transaction data aggregator; hosting the hub across many banks. 
Technology:  a screen scraper at the backend, providing a REST-like API that does not make use of essentials such as hypermedia, content type negotiation, or link relations
Functional:  Retail banking services such as accounts and transaction data.
License model:  ?




Teller.io (http://teller.io/)

Overview:  Transaction data API, acting as an api hub across many banks. 
Technology:  uses the banks mobile REST api to gain access to the customers transaction data and any options available in the banks mobile application, providing a REST API that makes use of hypermedia, content type negotiation, or link relations
Functional:  Retail banking services such as accounts and transaction data.
License model:  ?

Friday 25 September 2015

Creating adaptive APIs

Creating adaptive interaction APIs

No one can argue against the success of the internet.  Websites and the network protocol of the internet (HTTP) has been fantastically successful.  Yet there is still a significant amount of research and education required to be able to offer interaction APIs at the scale of web pages.

What is an interaction API?  If we boil it down, it is one that shares just the data and the allowed actions.  We are very used to this concept of allowed action on a webpage, but often seem to miss the requirement completely when the consumer is not a web browser.

Since 2013, we have been working on a language to define resources and the allowed interactions between those resources.  This language is not an API definition format, we have swagger, wadl, and many other formats for that already.  This is a language to allow us to spend more time thinking about when the links / actions should be available and less time learning / thinking about how to implement REST.  

We communicate these allowed actions as links within a RESTful architecture and allow user-agents / clients to ask for the data in their preferred format with content negotiation headers (Accept / Content-Type).   These API details and many others can be subtle, but make a huge difference to the loose coupling and ease of use for your API.

The following videos walk through many of the fundamentals of API design and the language we've defined for describing the resource interactions.  We are using the tooling available from Temenos for building these APIs, but the language and the hypermedia server implementation are available as open source.


Video 1 - Creating the service & Media Types 
(https://www.youtube.com/watch?v=eTmftTEpzSQ)
The series of videos explores the process of creating an API with the Temenos Interaction Framework Design Studio tooling. This first episode focuses on the basic service creation, the available media types (response formats) and the API browsers available out of the box.

Video 2 - API Design 
The series of videos explores the process of creating an API with the Temenos Interaction Framework Design Studio tooling. This second episode focuses on the API Design for data services, browsable API docs and interaction services.

Video 3 - API Management 
The series of videos explores the process of creating an API with the Temenos Interaction Framework Design Studio tooling. This third episode focuses on the API Management for publication to internal or external developers through API management products such as the Azure API Manager.

Video 4 – API Errors, Tests and Orchestration 
The series of videos explores the process of creating an API with the Temenos Interaction Framework Design Studio tooling. This fourth episode focuses on the API status codes, errors, integration tests, and API Orchestration for validation and a high level of automation.

Video 5 – API Flow control and screen control 

The series of videos explores the process of creating an API with the Temenos Interaction Framework Design Studio tooling. This fifth episode focuses on the APIs ability to control the flow and state of the client and the control of the screen.

Thursday 30 July 2015

Interaction Patterns

APIs, User-Agents, and Interaction Patterns

This blog provides an overview of the service call patterns typically found within any large scale, multi-channel interaction layer.  Here we define a service call as any interaction with an API endpoint.  That interaction is generally a request that expects a response and often times requires the use of more than one API endpoint to complete the client / user-agent request.  Despite the need to make several calls to multiple APIs, the overall processing will generally appear to the user to be synchronous, i.e. a single request.  In this paper I attempt to highlight the requirements and constraints of each pattern and the affect on the the users experience.


What is an interaction layer?


An interaction layer solves a general many to many problem that occurs within many fields of software intensive systems.  The interaction layer specialises in user interface to system processing and although similar to enterprise integration, which also involves routing and transformation, it is fundamentally different because it involves a person.  Interaction from a user generally requires a response; furthermore that user can understand the meaning of a response, whereas integration between two systems does not generally require a response and a system cannot understand the meaning of unexpected responses.

Figure 1 - Logical interaction architecture view



Interaction Layer Implementation


Whilst the diagram in Figure 1 - Logical interaction architecture view provides a good basis for understanding the elements of the interaction layer, it is sometimes more meaningful to see how the system might be implemented with components that handle the transformation, routing, and description of the model.  See Figure 2 - Interaction Framework Components.  NB - this is the component view of the IRIS implementation of an interaction framework.

Figure 2 - Interaction Framework Components


Transactional service orchestration

This pattern describes a scalable architecture designed to address a requirement where a resource must be created in 2 or more resource managers, a resource must be consistent across 2 or more resource managers, or a validation rule can only be processed following the completion of a transaction in another resource manager.  E.g. Anti-money laundering, Master data management, ATM or any over the counter style transaction where we must process the full value chain.  To scale with this requirement we must not serialise the transaction across two resource managers or introduce a two phase commit.

Figure 3 - transactional service orchestration

Figure 3 - transactional service orchestration
1. User-agent requests create or update operation; waits for a response
2.      Interaction layer requests create or update operation
3.      Interaction layer immediately begins to poll for a result
4.      Two one-way message between resource managers


Transactional no orchestration

This pattern describes a scalable architecture designed to address a requirement where a resource must be created in 2 resource managers and there is no transfer of risk.  A resource must be consistent across 2 or more resource managers, or a validation rule can only be processed following the completion of a transaction in another resource manager.  E.g. order management.  To scale with this requirement we must not serialise the transaction across two resource managers or introduce a two phase commit.

Figure 4 - transactional service no orchestration

Figure 4 - transactional service no orchestration
1.      User-agent requests create or update operation; waits for a response
2.      Interaction layer requests create or update operation
3.      Interaction layer immediately begins to poll for a result
4.      Single one-way message between resource managers


Validate and commit

This pattern describes a scalable architecture designed to address a requirement where a resource must be validated before being created in a resource manager.  E.g. a business validation with an external service such as an address.  All user-agents and services exposed share the same validation logic, the call to the validation service is permissible as it does not perform any modification and therefore does not serialise the request across two resource managers or require a two phase commit.

Figure 5 - validate and commit

Figure 5 - validate and commit
1.      User-agent requests create or update operation; waits for a response.
2.      Interaction layer validates the request with the external service
3.      Interaction layer requests create or update operation within a single resource manager.

 

Validate

This pattern addresses a similar requirement to the ‘validate + commit’ pattern, and describes a scalable and low latency architecture where a resource is validated in multiple resource managers.  E.g. a business validation with an external service such as an address, and the validation of the financial transaction.  All user-agents and services exposed share the same validation logic, the validations can be performed in parallel.


Figure 6 - validate

Figure 6 - validate
1.      User-agent requests validation operation; waits for a response.
2.      Interaction layer validates the request with the external service; in parallel validates the request with the resource manager.

Enrichment

This pattern describes a scalable architecture designed to address a requirement where a screen is enriched with some external data to make a decision or improve the data entry.  E.g. estimated rate, an address finder, or a dynamic screen adaption based on metadata.

Figure 7 - enrichment with javascript library

Figure 7 - enrichment with javascript library
1.      User-agent requests enrichment directly from the client; waits for a response.
2.      User-agent requests create or update operation; waits for a response.
3.      Interaction layer requests create or update operation within a single resource manager.


Figure 8 - enrichment with interaction layer routing

Figure 8 - enrichment with interaction layer routing
1.      User-agent requests enrichment from the interaction layer; waits for a response.
2.      Interaction layer requests enrichment from external service
3.      User-agent requests create or update operation; waits for a response.
4.      Interaction layer requests create or update operation within a single resource manager.





Mashup

This pattern describes a scalable architecture designed to address a requirement where a screen is filled with data from multiple sources.  E.g. a single customer view, orders and holdings view, and complex composite screens.  To scale with this requirement we adopt the constraint that we only mashup whole resources, we do not aggregate results into rows. 

Figure 9 - mashup interaction layer

Figure 9 - mashup interaction layer
1.      User-agent requests data; waits for a response.
2.      Interaction layer issues requests in parallel with all data providers and return embedded resources within expanded links.  See HAL+JSON embedded resources for example.
NB – user agent waits at least as long as the slowest response.


Figure 10 - mashup ui layer, controlled by interaction

Figure 10 - mashup ui layer, controlled by interaction
1.      User-agent requests resource; immediately renders screen; issues further requests by dereferencing links that were provided by the interaction layer.
2.      User-agent requests resources in parallel; renders as available
3.      Interaction layer issues requests to data provider
NB – rapid time to first byte (something displaying on the screen) provides an optimal user experience; see data as soon as it becomes available.



Anti-patterns

The following anti-patterns are common solutions to some of the above requirements that are ineffective or non-scalable.

Transactional update with call-out and two phase commit

This pattern describes a non-scalable architecture designed to address a requirement where a resource must be created in 2 or more resource managers, a resource must be consistent across 2 or more resource managers, or a validation rule can only be processed following the completion of a transaction in another resource manager.  E.g. Anti-money laundering, Master data management, order management.  This approach does not scale because it ties up scare resources in the resource manager, we serialise the transaction across two resource managers and require a two phase commit to remain consistent.

Figure 8 - Transactional update with call-out and two phase commit

Figure 8 - Transactional update with call-out and two phase commit
1.      User-agent requests create or update operation
2.      Resource manager requests create or update operation





Monday 28 October 2013

The making of Restbucks

The making of Restbucks

Even great coffee starts with a very small seed.  In this blog post we'll be implementing the worlds best known RESTful coffee shop with IRIS.  IRIS is an open source project for create Interaction, Reporting and Information Services; what better example for our project than a nice cup of Restbucks coffee.  If you happen to be reading this post with a cuppa, Restbucks will be ready for service by the time you finish.

Entity Relationships

We're going to kick start our example with a simple Entity Relationship diagram and follow most of the steps in the Quickstart.  The Restbucks database contains Orders and Payments:



It seems a little odd for a Java project to start an example using Visual Studio, but one of the easiest ways to get an IRIS project started is to create services from an EDMX file.  Visual Studio is still the best tool to create our Restbucks EDMX file.  With only a few minor alterations to remove unsupported annotations and keeping complex types out of the picture for the moment it looks as follows:

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
    <edmx:DataServices m:DataServiceVersion="1.0">
        <Schema xmlns="http://schemas.microsoft.com/ado/2006/04/edm" Namespace="RestbucksModel">
        <EntityContainer Name="Restbucks" m:IsDefaultEntityContainer="true">
          <EntitySet Name="Orders" EntityType="RestbucksModel.Order" />
          <EntitySet Name="Payments" EntityType="RestbucksModel.Payment" />
          <AssociationSet Name="OrderPayment" Association="RestbucksModel.OrderPayment">
            <End Role="Order" EntitySet="Orders" />
            <End Role="Payment" EntitySet="Payments" />
          </AssociationSet>
        </EntityContainer>
        <EntityType Name="Order">
          <Key>
            <PropertyRef Name="Id" />
          </Key>
          <Property Type="Int32" Name="Id" Nullable="false" />
          <Property Type="String" Name="location" Nullable="false" />
          <NavigationProperty Name="Payment" Relationship="RestbucksModel.OrderPayment" FromRole="Order" ToRole="Payment" />
          <Property Type="String" Name="name" Nullable="false" />
          <Property Type="String" Name="milk" Nullable="false" />
          <Property Type="Int16" Name="quantity" Nullable="false" />
          <Property Type="String" Name="size" Nullable="false" />
        </EntityType>
        <EntityType Name="Payment">
          <Key>
            <PropertyRef Name="Id" />
          </Key>
          <Property Type="Int32" Name="Id" Nullable="false" />
          <Property Type="String" Name="authorisationCode" Nullable="false" />
          <NavigationProperty Name="Order" Relationship="RestbucksModel.OrderPayment" FromRole="Payment" ToRole="Order" />
        </EntityType>
<Association Name="OrderPayment">
<End Type="RestbucksModel.Order" Role="Order" Multiplicity="1" />
<End Type="RestbucksModel.Payment" Role="Payment" Multiplicity="0..1" />
                <ReferentialConstraint>
                <Principal Role="Order">
                <PropertyRef Name="Id"/>
                </Principal>
                <Dependent Role="Payment">
                <PropertyRef Name="Id"/>
                </Dependent>
                </ReferentialConstraint>
</Association>
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>


Generating the project mock responder

We now use the above EDMX to generate a simple mock database and mock responder services.

$ mvn interaction-sdk:gen

Once we've executed the generation step we can immediately try to start our project with 'jetty:run'.  Using the EDMX provided here in this post does result in one or two errors initially because we want our service to be called Orders; this is a reserved word in SQL.  Therefore we need to make one minor correction to the generated table name.

$ mvn clean package jetty:run


21:38:04.177 [main] DEBUG o.h.tool.hbm2ddl.SchemaExport - create table Order (Id integer not null, location varchar(255), milk varchar(255), name varc
har(255), quantity integer, size varchar(255), primary key (Id))
21:38:04.178 [main] ERROR o.h.tool.hbm2ddl.SchemaExport - Unsuccessful: create table Order (Id integer not null, location varchar(255), milk varchar(2
55), name varchar(255), quantity integer, size varchar(255), primary key (Id))
21:38:04.180 [main] ERROR o.h.tool.hbm2ddl.SchemaExport - Unexpected token: ORDER in statement [create table Order]
21:38:04.180 [main] DEBUG o.h.tool.hbm2ddl.SchemaExport - create table Payment (Id integer not null, authorisationCode varchar(255), primary key (Id))

21:38:04.186 [main] DEBUG o.h.tool.hbm2ddl.SchemaExport - alter table Order add constraint FK48E972EB5B9E338 foreign key (Id) references Payment
21:38:04.186 [main] ERROR o.h.tool.hbm2ddl.SchemaExport - Unsuccessful: alter table Order add constraint FK48E972EB5B9E338 foreign key (Id) references
 Payment
21:38:04.187 [main] ERROR o.h.tool.hbm2ddl.SchemaExport - Unexpected token: ORDER in statement [alter table Order]
21:38:04.188 [main] DEBUG o.h.tool.hbm2ddl.SchemaExport - alter table Payment add constraint FK3454C9E659675240 foreign key (Id) references Order
21:38:04.189 [main] ERROR o.h.tool.hbm2ddl.SchemaExport - Unsuccessful: alter table Payment add constraint FK3454C9E659675240 foreign key (Id) referen
ces Order
21:38:04.190 [main] ERROR o.h.tool.hbm2ddl.SchemaExport - Unexpected token: ORDER in statement [alter table Payment add constraint FK3454C9E659675240
foreign key (Id) references Order]
...
Oct 27, 2013 9:38:05 PM com.temenos.interaction.sdk.util.ResponderDBUtils fillDatabase
SEVERE: Failed to insert SQL statements.
java.sql.SQLException: Unexpected token: ORDER in statement [INSERT INTO Order]
        at org.hsqldb.jdbc.Util.sqlException(Unknown Source)
        at org.hsqldb.jdbc.jdbcStatement.fetchResult(Unknown Source)
        at org.hsqldb.jdbc.jdbcStatement.executeUpdate(Unknown Source)
        at com.temenos.interaction.sdk.util.ResponderDBUtils.fillDatabase(ResponderDBUtils.java:74)


Modify Order.java
@Entity
@Table(name="rb_order")
public class Order {

Modify responder_insert.sql
INSERT INTO `rb_order`(`Id` , `location` , `name` , `milk` , `quantity` , `size`) VALUES('1' , 'abc' , 'abc' , 'abc' , '1' , 'abc');


Data Service into Interaction Service

By default the interaction SDK creates an OData service when generated from an EDMX.  OData is a good example of a Data Service - it has links between entities.  However, to become an Interaction Service we need to use these links to guide our client interactions.  You can open the IRIS default OData javascript client http://localhost:8080/responder and you should see the following :



Restbuck Interactions and State Machine

If we take a moment to refer back to Rest In Practice, Section 5.4.1. The Restbucks Domain Application Protocol, we'll see a very useful diagram that describes our client interactions with Restbucks.  As the book points out, this diagram is great in terms of understanding the HTTP requests and responses, but to codify the service we need to think in terms of the state machine.

Interactions:

State machine:


If we have to think in terms of a state machine, why do we seldom see services written in terms of a state machine?  The Resource Interaction Model (RIM) is a domain specific language to help us do just that.  The RIM language is intended to be a conceptual level language that removes the need to understand the HTTP implementation details; at the same time this means we can ensure the RIM implementation is logically correct according to the RESTful constraints - by using verbs, status codes, representations, and links appropriately.


Resource Interaction Model

To turn the generated Restbucks Data Service into an Interaction Service we need to edit the src/main/resources/Restbucks.rim and implement the states from Figure 5-5.  Your first task will be to remove the generated CRUD states, and after some small modifications your Restbucks.rim will now look as follows:

RIM visualisation plugin



Restbucks.rim

domain RestbucksModel {
rim Restbucks {

event DELETE {
method: DELETE
}
event GET {
method: GET
}
event POST {
method: POST
}
event PUT {
method: PUT
}

command CreateEntity
command DeleteEntity
command GETEntities
command GETEntity
command GETException
command GETNavProperty
command GETServiceDocument
command NoopGET
command UpdateEntity

initial resource ServiceDocument {
type: item
entity: ServiceDocument
view { GETServiceDocument }
path "/"
GET -> Orders
GET -> Payments
GET -> shop
}

resource shop {
type: item
entity: ServiceDocument
view { NoopGET }
path "/shop"
POST -> OrderCreated
}


resource Orders {
type: collection
entity: Order
view { GETEntities }
path "/Orders()"
POST -> OrderCreated
GET *-> order id=Id
GET title="Payment" *-> payment
PUT *-> OrderUpdated
DELETE *-> OrderCancelled
}

resource order {
type: item
entity: Order
view { GETEntity }
path "/Orders({Id})"
GET title="Payment" -> payment
// Can only update or delete if we haven't paid
PUT -> OrderUpdated (NOT_FOUND(payment))
DELETE -> OrderCancelled (NOT_FOUND(payment))
POST -> PaymentAccepted (NOT_FOUND(payment))
}

resource OrderCancelled {
type: item
entity: Order
actions { DeleteEntity }
relations { "http://relations.restbucks.com/cancel" }
path "/Orders({Id})"
}

resource OrderUpdated {
type: item
entity: Order
actions { UpdateEntity }
relations { "http://relations.restbucks.com/update" }
path "/Orders({Id})"
}

resource OrderCreated {
type: item
entity: Order
actions { CreateEntity }
path "/Orders()"
GET --> order (OK(order))
}

resource Payments {
type: collection
entity: Payment
view { GETEntities }
path "/Payments()"
GET *-> payment
GET title="Order" *-> order
}

resource payment {
type: item
entity: Payment
view { GETEntity }
path "/Payments({Id})"
GET title="Order" -> order
}

resource PaymentAccepted {
type: item
entity: Payment
actions { CreateEntity }
relations { "http://relations.restbucks.com/payment" }
path "/Payments()"
GET --> payment (OK(payment))
}

}
}


Ready for service

Our shop is now ready for business.  Let's start our server and POST an order.  Using Postman POST the following entry, with Content-Type application/atom+xml to http://localhost:8080/responder/interaction-hateoas-restbucks.svc/Orders()

<?xml version='1.0' encoding='utf-8'?>
<entry 
    xmlns="http://www.w3.org/2005/Atom" 
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
    xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xml:base="http://localhost:8080/responder/interaction-hateoas-restbucks.svc/">
    <id>http://localhost:8080/responder/interaction-hateoas-restbucks.svc/Orders(1)</id>
    <title type="text" />
    <updated>2013-10-28T11:57:15Z</updated>
    <author>
        <name />
    </author>
    <category term="RestbucksModel.Order" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <content type="application/xml">
        <m:properties>
            <d:size>abc</d:size>
            <d:milk>abc</d:milk>
            <d:name>abc</d:name>
            <d:location>abc</d:location>
            <d:quantity m:type="Edm.Int32">1</d:quantity>
        </m:properties>
    </content>
</entry>


You will receive the following response 201 Created:

<?xml version='1.0' encoding='utf-8'?>
<entry 
    xmlns="http://www.w3.org/2005/Atom" 
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
    xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xml:base="http://localhost:8080/responder/interaction-hateoas-restbucks.svc/">
    <id>http://localhost:8080/responder/interaction-hateoas-restbucks.svc/Orders(1001)</id>
    <title type="text" />
    <updated>2013-10-28T23:36:07Z</updated>
    <author>
        <name />
    </author>
    <link rel="self" type="application/atom+xml;type=entry" title="order" href="Orders(1001)" />
    <link rel="http://relations.restbucks.com/update" type="application/atom+xml;type=entry" title="OrderUpdated" href="Orders(1001)" />
    <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Payment" type="application/atom+xml;type=entry" title="Payment" href="Payments(1001)" />
    <link rel="http://relations.restbucks.com/payment" type="application/atom+xml;type=entry" title="PaymentAccepted" href="Payments()" />
    <link rel="http://relations.restbucks.com/cancel" type="application/atom+xml;type=entry" title="OrderCancelled" href="Orders(1001)" />
    <category term="RestbucksModel.Order" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <content type="application/xml">
        <m:properties>
            <d:milk>abc</d:milk>
            <d:location>abc</d:location>
            <d:name>abc</d:name>
            <d:size>abc</d:size>
            <d:Id m:type="Edm.Int32">1001</d:Id>
            <d:quantity m:type="Edm.Int32">1</d:quantity>
        </m:properties>
    </content>
</entry>


Notice that you can pay this Order by using the 'payment' link:
    <link rel="http://relations.restbucks.com/payment" type="application/atom+xml;type=entry" title="PaymentAccepted" href="Payments()" />


This implementation of the Restbucks API is a nice little Hypermedia API example, but it could be improved in a few ways.  The first problem is how to get the initial Entry to post to /Orders.  I prefer to coin a new link relation for this task e.g. http://relations.restbucks.com/new bound to /Orders/new.  We could then default a few details and provide an Entry that could be filled out and POSTed back.

Another issue is the 'application/atom+xml' media type.  Perhaps I would like a json payload.  IRIS comes with a few different media type Providers, including 'application/hal+xml' and 'application/hal+json'.  HAL is an xml or json media type suitable for Hypermedia API's because it specifies the all important syntax for links.  The IRIS server can simply be configured with the HalProvider by modifying the spring-beans.xml as follows:

<bean id="halProvider" class="com.temenos.interaction.media.hal.HALProvider">
    <constructor-arg ref="edmMetadata" />
        <constructor-arg ref="stateMachine" />
</bean>
<bean class="com.temenos.interaction.winkext.RegistrarWithSingletons">
<property name="singletons">
<list>
<ref local="atomProvider" />
<ref local="edmxProvider" />
<ref local="serviceDocumentProvider" />
<ref local="errorProvider" />
<ref local="xhtmlProvider" />
<ref local="halProvider" />
  </list>
    </property>
        <property name="serviceRoots">
            <list>
                <ref local="ServiceRoot" />
                <ref local="Metadata" />
            </list>
        </property>
</bean>

You will also need to update your pom.xml to add the HALProvider dependency:

    <!-- Add dependency for our hal provider -->
    <dependency>
        <groupId>com.temenos.interaction</groupId>
        <artifactId>interaction-media-hal</artifactId>
        <version>0.4.0-SNAPSHOT</version>
        <scope>runtime</scope>
    </dependency>


With very little effort you could now use the HAL Browser to understand your API:
I hope you enjoyed your coffee.