Note

Haley: A HAL Resource Builder in Java

Published by Michael Hartle on 2019-04-16
Tagged with Hypertext Application Language (HAL) Hypertext As The Engine Of Application State (HATEOAS) Representational State Transfer (REST) JavaScript Object Notation (JSON) Web Jackson Java

Manually implementing the generation of HAL resources for REST/HATEOAS-based web services in Java can be tedious. To simplify the implementation, we have published our library Haley under the Apache License 2.0 on Github.

Overview

Haley offers builder classes with a fluent API, allowing even complex JSON-HAL-Resources to be elegantly implemented in web service controllers in Spring- or Jersey-based projects. The only dependency of Haley is Jackson for the serialization of HAL resources.

The library supports all specified features as shown in the draft specification of HAL, such as namespacing support through CURIEs, links and embedding of resources through methods on the builders. The library is available as project on Github under the Apache License 2.0.

Example

To showcase the usage of Haley, we use the example of a HAL resource that represents a page in a sequence of pages, and has a single item as another HAL resource on the page.

In HAL, the identity of a resource and the relation to previous and next pages is represented through links; if there is a previous or a next page, the respective link is available. The contained item is represented through an embedding of the item resource.

After importing the builder classes from the package com.hartle_klug.haley, this example might be implemented as

    final Resource pageResource =
        ResourceBuilder.use(
            RepresentationBuilder.use()
            .property(PropertyBuilder.use("page", pageNumber).build())
            .build())
        .linkSelf(
            LinkBuilder.use("http://company.com/page/" + pageNumber)
            .profile("http://company.com/ns/page")
            .build())
        .link("previous",
            pageNumber > 0 ?
                LinkBuilder.use("http://company.com/page/" + (pageNumber - 1))
                .profile("http://company.com/ns/page")
                .build() :
                null)
        .link("next",
            pageNumber < maxPageNumber ?
                LinkBuilder.use("http://company.com/page/" + (pageNumber + 1))
                .profile("http://company.com/ns/page")
                .build() :
                null)
        .embedd("item",
            ResourceBuilder.use(
                RepresentationBuilder.use()
                .build())
            .linkSelf(
                LinkBuilder.use("http://company.com/item/" + itemNumber)
                .build())
            .build())
        .build();

Actually, link building through string concatenation is not to be seen as best practice, as it is just done here for demonstration purposes. With corresponding variable values, the resource can be serialized through Jackson, yielding

{
  "page": 1,
  "_links": {
    "self": {
      "profile": "http://company.com/ns/page",
      "href": "http://company.com/page/1"
    },
    "previous": {
      "profile": "http://company.com/ns/page",
      "href": "http://company.com/page/0"
    },
    "next": {
      "profile": "http://company.com/ns/page",
      "href": "http://company.com/page/2"
    }
  },
  "_embedded": {
    "item": {
      "_links": {
        "self": {
          "href": "http://company.com/item/99"
        }
      }
    }
  }
}

If you have tried our library or even used it productively, just drop us a line - we would like to hear from you!



Next post: Harpocrates: A paper-based backup and recovery tool
Previous post: Model-Driven Architecture with TextUML, Ecore, OVFTo and Acceleo