Notiz

Haley als HAL Resource Builder unter Java

Veröffentlicht von Michael Hartle am 16.04.2019
Getagged mit Hypertext Application Language (HAL) Hypertext As The Engine Of Application State (HATEOAS) Representational State Transfer (REST) JavaScript Object Notation (JSON) Web Jackson Java

Die manuelle Erzeugung von HAL-Resourcen für REST/HATEOAS-basierte Web Services unter Java kann aufwändig werden. Um die Erzeugung zu vereinfachen, haben wir unsere Bibliothek Haley unter der Apache License 2.0 auf Github veröffentlicht.

Überblick

Haley bietet Builder-Klassen mit einer Fluent API, mit deren Hilfe auch komplexe Anwendungsfälle für JSON-HAL-Resourcen elegant in Web Service Controllern in Spring- oder Jersey-basierten Projekten implementiert werden können. Haley setzt dabei nur auf Jackson für die Serialisierung der HAL-Resourcen auf.

Die in der Draft-Spezifikation von HAL beschriebene Namespace-Unterstützung durch CURIEs, die Verlinkung oder die Einbettung von weiteren Resourcen wird von entsprechenden Builder-Methoden unterstützt.

Die Bibliothek steht als Projekt auf Github unter der Apache License 2.0 zur Verfügung.

Beispiel

Ein Beispiel für den Einsatz von Haley ist eine HAL-Resource, welche eine Seite in einer Folge von Seiten repräsentiert, und jeweils einen Eintrag hat, welcher wiederum eine HAL-Resource ist.

In HAL wird die Definition der eigenen Identität einer Resource sowie die Verknüpfung zu Vorgänger- und Nachfolger-Seiten jeweils mittels eines Links repräsentiert, welcher vorhanden ist, falls es jeweils eine Vorgänger- oder Nachfolger-Seite gibt. Der enthaltene Eintrag wird über eine Einbettung ("embedded") realisiert.

Hat man die Builder im Package com.hartle_klug.haley importiert, lässt sich dies mittels Haley beispielsweise mit

    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();

implementieren, wobei die Link-Konstruktion durch Konkatenation von Strings hier nur der Anschaulichkeit dienen soll, und kein Best Practice ist. Mit entsprechenden Variablenwerten versehen kann die Resource dann via Jackson als

{
  "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"
        }
      }
    }
  }
}

serialisiert werden.

Falls Sie die Bibliothek ausprobiert haben oder gar praktisch einsetzen, dann würden wir uns freuen, von Ihnen und Ihren Erfahrungen zu hören!



Nächster Beitrag: Harpocrates: Papier-basierte Sicherung & Wiederherstellung