Skip to content

Latest commit

 

History

History
executable file
·
384 lines (286 loc) · 13.2 KB

README.adoc

File metadata and controls

executable file
·
384 lines (286 loc) · 13.2 KB

Creating a Hypermedia-driven RESTful Web Service

Explore how to use Hypermedia As The Engine Of Application State (HATEOAS) to drive your RESTful web service on top of Open Liberty.

What you’ll learn

You will learn how to use hypermedia to create a specific style of a response JSON, the contents of which are used to navigate your REST service. You’ll be building on top of a simple inventory REST service developed with MicroProfile technologies, providing a service at the following URL:

http://localhost:9080/inventory/hosts

The service responds with a JSON containing an array of registered hosts, each with a collection of HATEOAS links:

[
  {
    "hostname": "foo",
    "_links": [
      {
        "href": "http://localhost:9080/inventory/hosts/foo",
        "rel": "self"
      }
    ]
  },
  {
    "hostname": "bar",
    "_links": [
      {
        "href": "http://localhost:9080/inventory/hosts/bar",
        "rel": "self"
      }
    ]
  },
  {
  "hostname": "*",
  "_links": [
    {
      "href": "http://localhost:9080/inventory/hosts/*",
      "rel": "self"
    }
  ]
  }
]

What is HATEOAS?

Hypermedia As The Engine Of Application State (HATEOAS) is a unique constraint of REST architecture. The idea of HATEOAS is that, just like on any regular website, the end user is able to navigate your API by using simple links, and without the need to reference any documentation. In other words, your application tells the user where they can go and what they can access by providing them with a simple collection of links to other available resources.

Response JSON

When you build a RESTful web service, it is important to consider the style of your response files. Whether they are JSON files, XML files, or in some other format, a good practice is to always have them in a clean and organized form. In the context of HATEOAS, each resource must contain a link reference to itself, commonly referred to as self. Each link must also have a relationship associated with it, although no strict rules exist as to how this relationship must be formatted. The collection of such links must be contained with a _links hash, which itself must be a direct property of the resource object. The underscore is used so that the _links property does not collide with any existing fields named links. The structure of HATEOAS links that you will be using in this guide is the following one:

  "_links": [
    {
      "href": ,
      "rel":
    }
  ]

Focus on two different types of links. The first has a self relationship with the resource object, is generated whenever a host has been registered, and points to that host entry in the inventory:

  {
    "href": "http://localhost:9080/inventory/hosts/<hostname>",
    "rel": "self"
  }

The second link has a properties relationship with the resource object, is generated if the host system service is running, and points to it:

  {
    "href": "http://<hostname>:9080/system/properties",
    "rel": "properties"
  }

Other formats

Although you should stick to the previous format for the purpose of this guide, the link is also commonly a direct property of the relationship:

  "_links": {
      "self": "http://localhost:9080/inventory/hosts/<hostname>",
      "properties": "http://<hostname>:9080/system/properties"
  }

Creating the response JSON

Begin by building your response JSON, which is composed of the _links hash, as well as the name of the host machine.

Linking to inventory contents

First, you must tweak your existing request handlers in the InventoryResource class. Since the …​/inventory/hosts/ URL no longer responds with a JSON representation of the contents of your inventory, the listContents method can be discarded and instead be integrated into the getPropertiesForHost method:

link:finish/src/main/java/io/openliberty/guides/microprofile/InventoryResource.java[role=include]

The contents of your inventory are now under the * wildcard and reside at the following URL:

http://localhost:9080/inventory/hosts/*

Next, add a simple GET request handler that is responsible for handling all GET requests that are made to our target URL. This method responds with a JSON containing HATEOAS links:

link:finish/src/main/java/io/openliberty/guides/microprofile/InventoryResource.java[role=include]

You also need a UriInfo object, which you use to build your HATEOAS links:

link:finish/src/main/java/io/openliberty/guides/microprofile/InventoryResource.java[role=include]

The @Context annotation is a part of CDI and indicates a context injection.

Your new InventoryResource class is now finished. Next, let’s implement the getSystems method and build the response JSON object.

Linking to each available resource

Let’s implement the getSystems method in your InventoryManager class. This method accepts a target URL as an argument and returns a JSON object that contains HATEOAS links.

link:finish/src/main/java/io/openliberty/guides/microprofile/InventoryManager.java[role=include]

The buildHostJson helper method builds the actual JSON object. You use this method together with a simple map function to collect for each system the JSON object in an array.

Let’s implement the buildHostJson helper in the InventoryUtil class:

link:finish/src/main/java/io/openliberty/guides/microprofile/util/InventoryUtil.java[role=include]

You’re creating a JSON object that contains the name of your host system and the _links hash, which is generated separately in another helper:

link:finish/src/main/java/io/openliberty/guides/microprofile/util/InventoryUtil.java[role=include]

This helper accepts a host name and a target URL as arguments and builds a link that points to the inventory entry with a self relationship, as well as a link that points to the system service with a properties relationship:

Linking to inactive services or unavailable resources

Consider what happens when one of the return links does not work or when a link should be available for one object but not for another. In other words, it is important that a resource or service is available and running before it is linked in the _links hash.

Although this guide does not cover this case, you should nevertheless always make sure that the response code from a service is good before linking that service. Similarly, always make sure that the resource you’re trying to link is acceptable to access by the particular object you’re attaching it to.

Starting the application

To see the new application in action, run the Maven liberty:start-server command from the start directory:

cd start
mvn liberty:start-server

After the server is running, you can find your new Hypermedia-driven inventory service at the following URL:

Testing the hypermedia-driven RESTful web service

The inventory service that is now hypermedia-driven can be accessed at the following URLs:

The first URL returns the current contents of the inventory. The second returns the system properties for the given host name. These properties are retrieved from the inventory. If the inventory does not have an entry for the given host name, then the system service that is running on the same host name is called instead. The system properties retrieved from the system service are then stored in the inventory and returned.

If you have the servers running, you can access each of the previous URLs from your browser to test the application manually. However, you should always rely on automated tests since these tests will trigger a failure in the event a change introduces a defect. JUnit and the JAX-RS Client API provide a simple environment to test the application.

Setting up your tests

Create a test class src/test/java/it/io/openliberty/guides/hateoas/EndpointTest.java

Each test method must be marked with the @Test annotation.

You can use the @Before and @After annotations to perform any setup and teardown tasks for each of your individual tests.

link:finish/src/test/java/it/io/openliberty/guides/hateoas/EndpointTest.java[role=include]

You can find more detailed explanations on how to define your own system properties and how to access them in the MicroProfile guide.

Writing the tests

Normally, the execution order of the test methods cannot be controlled. However, each test method can instead be placed within a single container method. This method is the only method labelled @Test. The following test suite contains four test methods, which are run in the order they appear in the suite:

link:finish/src/test/java/it/io/openliberty/guides/hateoas/EndpointTest.java[role=include]

Create a test called testLinkForInventoryContents. This test is responsible for asserting that the correct HATEOAS link is created for the inventory contents.

link:finish/src/test/java/it/io/openliberty/guides/hateoas/EndpointTest.java[role=include]

Write a getResponse helper method to reuse the same line of code for retrieving a response from a given URL. This technique helps keep your code neat and organized:

link:finish/src/test/java/it/io/openliberty/guides/hateoas/EndpointTest.java[role=include]

Write another helper method called assertResponse. This method ensures that the response code that you receive is valid (200):

link:finish/src/test/java/it/io/openliberty/guides/hateoas/EndpointTest.java[role=include]

Create a test called testLinksForSystem. This test is responsible for asserting that the correct HATEOAS links are created for the localhost system. This method checks for both the self link, pointing to the inventory service, and the properties link, pointing to the system service running on the localhost.

link:finish/src/test/java/it/io/openliberty/guides/hateoas/EndpointTest.java[role=include]

Write a helper method called visitLocalhost. This method creates a GET request to the system service, registering localhost:

link:finish/src/test/java/it/io/openliberty/guides/hateoas/EndpointTest.java[role=include]

Running the tests

To rebuild and run the tests, navigate to the start directory and run the mvn clean install command from the command line.

# If the server is still running from previous steps, stop it first:
mvn liberty:stop-server

# Then run the following command:
mvn clean install

Some time might elapse before the tests finish running. If the tests pass, you will see the following output:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.hateoas.EndpointTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.086 sec - in it.io.openliberty.guides.hateoas.EndpointTest

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

Congratulations! You’re done!

You have just built and tested a hypermedia-driven RESTful web service on top of Open Liberty.