Using a HAL hypermedia API in an Angular App

Modern APIs are often realized in a RESTful way. Besides being stateless and using the correct HTTP verbs for specific actions, REST does not specify the response of a request. Hypermedia Formats are trying to overcome this issue by providing a discoverable API. Hypermedia Application Language is one format and abbreviates as HAL.

HAL is a set of conventions expressing hyperlinks in either JSON or XML. Resources returned by a HAL API contain a _links element hosting a self link and a link to resources. This makes HAL APIs discoverable as it is possible to navigate from one resource to another via the links provided within the resources knowing only a single entry point. This article describes how to use HAL hypermedia APIs in Angular.

Consuming a HAL API in an Angular app is pretty straight forward. Just use the Angular http API as you would for a http request.

private restQuery(): Observable<HypermediaResult> {
  return this.http.get('api-endpoint') // URI to the API
    .map(response => response.json() || new HypermediaResult())
    .share();
 }

As abstraction for all API responses we introduced the HypermediaResult class containing a _links element which acts as host for the self link and an array of links to resources.

export class HypermediaResult {
  _links: {
    self: {
      href: string
    },
    [s: string]: {
      href: string
    }
  };
}

We implemented a HAL API with JSON. As explained previous the response contains a self link and a link to a resource. In this particular case the leads resource.

{ "_links" : {
  "self" : {
    "href" : "http://www.clintr.com/api/search/"
  },
  "leads" : {
    "href" : "http://www.clintr.com/api/search/companies/leads{?query}"
}}}

To specify query parameters HAL makes use of templated URIs. The leads resource provides a query parameter named query. This makes query parameters transparent in the API. Leads could be retrieved by following request:

searchLeads(searchstring: string): Observable<HypermediaResult> {
  return this.restQuery().flatMap((hypermediaResult: HypermediaResult) => {
    let link = uriTemplates(hypermediaResult._links['leads'].href).fill({'query': searchString});
    return this.http.get(link);
    })
    .catch(this.handleError)
    .map(res => res.json() || new HypermediaResult());
}

As you might have noticed we are using the URI-Templates project instead of UrlSearchParams from the Angular http API. UrlSearchParams is not capable of handling templated URIs.

A pretty young project is ng-hal combining the Angular http API, URI-Templates and halfred providing a Navigator concept similar to Angular http and a shortcut for the observables. At the time of writing this project was not ready to use.

The http library from Angular does not have a support of templated URLs out of the box, but they are required to make query parameters transparent in API definitions. For future releases of Angular it would be great to have native support of templated URLs. So far they are not on the roadmap. Maybe future releases of ng-hal close this gap. For now using Angular and the URI-Templates lib is an easy solution to consume HAL APIs.

This post was written by: