GEDOPLAN
Jakarta EE (Java EE)Spring

Rest – HATEOAS + HAL

Jakarta EE (Java EE)Spring

REST-Webservices sind wohl die am weitesten verbreitete Schnittstellentechnologie die im WEB zu finden ist. Dank JSON als Datenformat bietet REST eine zustandslose und leichtgewichtige Möglichkeit Daten zwischen Anwendungen auszutauschen. HATEOAS (Hypermedia as the Engine of Application State) ist nun im Grunde keine weitere Technologie, sondern ein Konzept wie eine REST-Schnittstelle aufgebaut werden sollte.

Der Grundgedanke hinter HATEOAS ist, dass Clients in der Lage sind die Funktionen der Anwendungs-API zu verwenden ohne das diese fest verdrahtet im Client-Code sein müssen. Vergleichbar ist dies mit der menschlichen Nutzung einer Webseite. Wir besuchen einen Internetauftritt, erhalten Informationen, aber auch weiterführende Links über die wir weitere Funktionen/Seiten abrufen können. Das Prinzip lässt sich nahezu eins zu eins auf HATEOAS anwenden. Anstatt lediglich die angeforderten Informationen in der Datenstruktur von JSON zu erhalten, informiert uns die Anwendung ebenfalls über weiterführende Aktionen und Links.

Ein einfaches Beispiel ist z.B. die Abbildung von JPA Entitäten im JSON Format. Nehmen wir ein sehr einfaches Datenmodell aus zwei Entitäten: User und Message. Die Entitäten besitzen eine Bi-Direktionale Verbindung:

@Entity
public class Message {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  private Date date;

  private String message;

  @ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private User user;

------------------------------------------------------------------------

@Entity
public class User {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  private String username;

  @OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
  private List<Message> messages;

Bereits hier müssen wir uns Gedanken über die Umwandlung in ein JSON Format machen: ohne zusätzlichen Eingriff von unserer Seite könnten diese Entitäten bereits nicht in ein JSON Format umgewandelt werden, da die Bi-Direktionale Relation zu einer Endlosschleife bei der Umwandlung führen würde. Neben der Bildung von DTOs, richten sich die Möglichkeiten um dieses Problem zu beheben nach dem verwendeten JSON Parser (Jackson bietet z.B. Annotationen an um Felder zu ignorieren, Sub-Views auszuliefern,  solche Relationen zu kennzeichnen oder diese lediglich mit der entsprechenden ID auszuliefern). Eine klassischer JSON Output für unser “Message”-Objekt könnte nach diesem Prinzip so aussehen:

{
     "date": "1970-01-01T00:00:00.000+0000",
     "message": "Hello World",
     "user": 2
}

Anstatt das Userobjekt mit auszuliefern, bietet das JSON hier nur die entsprechende ID an. Wenn der Client auch die Benutzer-Information benötigt muss, dieser wissen, dass es sich bei dieser ID um eine User-ID handelt, zudem muss die entsprechende URL zum Abruf der User-Daten (z.B. ” http://…/user/2 “) im Client-Code festgelegt sein.

HAL

Zur Unterscheidung: HATEOAS ist der Architektur-Ansatz, HAL ist eine Spezifikation zur JSON-Syntax der Link-Relationen. Neben HAL gibt es noch einige Alternativen (Collection+JSON, Hydra…). HAL findet z.B. Verwendung in “Spring HATEOAS”. Mittels “HAL” können die Informationen nun verlinkt werden und der Client damit in die Lage versetzt werden die benötigen zusätzlichen Informationen abzurufen, ohne die konkreten URLS selber zusammenzusetzen.

Unser Message-Objekt könnte mittels “HAL” dann wie folgt aussehen:

{
    "date": "1970-01-01T00:00:00.000+0000",
    "message": "Hello World",
    "_links": {
        "self": {
            "href": "http://localhost:8080/msg/2"
        },
        "user": {
            "href": "http://localhost:8080/msg/2/user"
        }
    }
}

Header Links

Eine andere Möglichkeit besteht darin Links im HTTP Header zu verankert. Dies lässt sich auch mit JAX-RS direkt erledigen. Ein einfaches Beispiel um innerhalb der Rest-Methode einen Link der Response hinzuzufügen könnte so aussehen:

  @Context
  UriInfo uriInfo;

  @GET
  @Path("hal")
  public Response getHelloHAL() {
    DemoEntity demo = new DemoEntity(1, "Hello World");
    return Response.ok(demo).link(uriInfo.getBaseUri().resolve("login"), "login").build();
  }

Der Header wird dann um einen entsprechenden Eintrag erweitert und enthält den angegebenen Link:

...
link <http://localhost:8080/angular-jwt-1.0-SNAPSHOT/rest/login>; rel="login"
...

Im nächsten Artikel werfen wir einen Blick auf Spring-Boot und dessen Möglichkeiten HATEOAS und HAL mit sehr wenig Aufwand in der eigenen Anwendung zu verwenden.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Bitte füllen Sie dieses Feld aus.
Bitte füllen Sie dieses Feld aus.
Bitte gib eine gültige E-Mail-Adresse ein.
Sie müssen den Bedingungen zustimmen, um fortzufahren.

Autor

Diesen Artikel teilen

LinkedIn
Xing

Gibt es noch Fragen?

Fragen beantworten wir sehr gerne! Schreibe uns einfach per Kontaktformular.

Kurse

weitere Blogbeiträge

Work Life Balance. Jobs bei Gedoplan

We are looking for you!

Lust bei GEDOPLAN mitzuarbeiten? Wir suchen immer Verstärkung – egal ob Entwickler, Dozent, Trainerberater oder für unser IT-Marketing! Schau doch einfach mal auf unsere Jobseiten! Wir freuen uns auf Dich!

Work Life Balance. Jobs bei Gedoplan

We are looking for you!

Lust bei GEDOPLAN mitzuarbeiten? Wir suchen immer Verstärkung – egal ob Entwickler, Dozent, Trainerberater oder für unser IT-Marketing! Schau doch einfach mal auf unsere Jobseiten! Wir freuen uns auf Dich!