HalBuilder 1.0.1 released
Last night I pushed out the first public release of my Java based Hypertext Application Language (HAL) parser/generator library to Maven Central:
<dependency>
<groupId>com.theoryinpractise</groupId>
<artifactId>halbuilder</artifactId>
<version>1.0.1</version>
</dependency>
The HalBuilder library provides an API for both generating, and consuming HAL based resource representations. Using the library, we can write the following code (examples are using Jetbrains Kotlin):
val gadgetForumOwner = openResource("http://localhost:4567/")
.follow("forums")
.findResourceByIdProperty("gadgets")
.follow("self")
.get("owner").get()
The above snippet uses four custom helper/extension methods outside of the base library: openResource, follow, and findResourceByIdProperty which are defined as:
inline fun openResource(href: String) : ReadableResource {
val stream = httpClient.prepareGet(href)?.execute()
?.get()?.getResponseBodyAsStream().sure()
return factory.newResource(InputStreamReader(stream)).sure();
}
inline fun Link.openResource() : ReadableResource {
return openResource(this.getHref().sure());
}
inline fun ReadableResource.follow(rel: String) : ReadableResource {
return this.getLinkByRel(rel)?.get()?.openResource().sure();
}
inline fun ReadableResource.findResourceByIdProperty(id: String) : ReadableResource {
return this.getResources()?.findFirst(
{ it -> id.equals(it?.get("id")?.get()) }).sure()
}
Our example application REST API is a mock “GeekZone” forum server, when we open the initial resource at http://localhost:4567/ (our only fixed entry URL) we’re returned a resource with a link telling us where the forums resource can be found:
<resource href="http://localhost:4567/">
<link rel="forums" href="http://localhost:4567/forums" />
</resource>
When we follow the link, a resource containing a set of embedded forum resources is returned:
<resource href="http://localhost:4567/forums">
<resource href="http://localhost:4567/forums/offtopic" rel="forum self">
<description>Anything goes baby!</description>
<id>offtopic</id>
</resource>
<resource href="http://localhost:4567/forums/gadgets" rel="forum self">
<description>Gadgets and Toys</description>
<id>gadgets</id>
</resource>
</resource>
The extension method findResourceByIdProperty walks the embedded resources looking for a matching id property. Once we’ve identified the embedded resource we wish to explore further, if the embedded representation’s content doesn’t satisfy our requirements, we can follow the self link to get the full representation:
<resource href="http://localhost:4567/forums/gadgets">
<link rel="forums" href="http://localhost:4567/forums" />
<link rel="rename" href="http://localhost:4567/forums/gadgets/rename" />
<description>Gadgets and Toys</description>
<id>gadgets</id>
<name>Gadget Talk</name>
<owner>example@example.com</owner>
</resource>
and then finally get the owner property.
The uniform nature of the HAL specification – a common structure and processing model of resources, links, and embedded resources means we can remove a large portion of ambiguity which often plagues REST based APIs.
Unfortunately HAL’s still not the saviour of everything REST, there’s still plenty of other questions surrounding your API to be decided.
A followup post will expand on how to use Halbuilder, and how resource ‘requirements’ are satisfied.