Eine Einführung in den Frühling HATEOAS

REST Top

Ich habe gerade den neuen Learn Spring- Kurs angekündigt , der sich auf die Grundlagen von Spring 5 und Spring Boot 2 konzentriert:

>> Überprüfen Sie den Kurs

1. Übersicht

In diesem Artikel wird der Prozess zum Erstellen eines hypermediengesteuerten REST-Webdiensts mithilfe des Spring HATEOAS-Projekts erläutert.

2. Spring-HATEOAS

Das Spring HATEOAS-Projekt ist eine Bibliothek von APIs, mit denen wir auf einfache Weise REST-Darstellungen erstellen können, die dem Prinzip von HATEOAS (Hypertext als Engine of Application State) folgen.

Im Allgemeinen impliziert das Prinzip, dass die API den Client durch die Anwendung führen sollte, indem relevante Informationen über die nächsten möglichen Schritte zusammen mit jeder Antwort zurückgegeben werden.

In diesem Artikel erstellen wir ein Beispiel mit Spring HATEOAS mit dem Ziel, Client und Server zu entkoppeln und der API theoretisch zu ermöglichen, ihr URI-Schema zu ändern, ohne Clients zu beschädigen.

3. Vorbereitung

Fügen wir zunächst die Spring HATEOAS-Abhängigkeit hinzu:

 org.springframework.boot spring-boot-starter-hateoas 2.1.4.RELEASE 

Wenn wir Spring Boot nicht verwenden, können wir unserem Projekt die folgenden Bibliotheken hinzufügen:

 org.springframework.hateoas spring-hateoas 0.25.1.RELEASE   org.springframework.plugin spring-plugin-core 1.2.0.RELEASE 

Wie immer können wir in Maven Central nach den neuesten Versionen des Starters HATEOAS, den Spring-Hateoas und den Spring-Plugin-Core-Abhängigkeiten suchen.

Als nächstes haben wir die Kundenressource ohne Spring HATEOAS-Unterstützung:

public class Customer { private String customerId; private String customerName; private String companyName; // standard getters and setters } 

Und wir haben eine Controller-Klasse ohne Spring HATEOAS-Unterstützung:

@RestController @RequestMapping(value = "/customers") public class CustomerController { @Autowired private CustomerService customerService; @GetMapping("/{customerId}") public Customer getCustomerById(@PathVariable String customerId) { return customerService.getCustomerDetail(customerId); } } 

Schließlich die Darstellung der Kundenressourcen :

{ "customerId": "10A", "customerName": "Jane", "customerCompany": "ABC Company" } 

4. Hinzufügen von HATEOAS-Unterstützung

In einem Spring HATEOAS-Projekt müssen wir weder den Servlet-Kontext nachschlagen noch die Pfadvariable mit dem Basis-URI verketten.

Stattdessen bietet Spring HATEOAS drei Abstraktionen zum Erstellen des URI - RepresentationModel, Link und WebMvcLinkBuilder . Wir können diese verwenden, um die Metadaten zu erstellen und sie der Ressourcendarstellung zuzuordnen.

4.1. Hinzufügen von Hypermedia-Unterstützung zu einer Ressource

Das Projekt stellt eine Basisklasse namens RepresentationModel bereit , von der beim Erstellen einer Ressourcendarstellung geerbt werden kann:

public class Customer extends RepresentationModel { private String customerId; private String customerName; private String companyName; // standard getters and setters } 

Die Kundenressource erstreckt sich von der RepresentationModel- Klasse, um die add () -Methode zu erben . Sobald wir einen Link erstellt haben, können wir diesen Wert einfach auf die Ressourcendarstellung setzen, ohne neue Felder hinzuzufügen.

4.2. Links erstellen

Spring HATEOAS bietet ein Link- Objekt zum Speichern der Metadaten (Speicherort oder URI der Ressource).

Zuerst erstellen wir manuell einen einfachen Link:

Link link = new Link("//localhost:8080/spring-security-rest/api/customers/10A"); 

Das Link- Objekt folgt der Atom- Link-Syntax und besteht aus einem rel, das die Beziehung zur Ressource und dem href- Attribut identifiziert, das der eigentliche Link selbst ist.

So sieht die Kundenressource jetzt aus, da sie den neuen Link enthält:

{ "customerId": "10A", "customerName": "Jane", "customerCompany": "ABC Company", "_links":{ "self":{ "href":"//localhost:8080/spring-security-rest/api/customers/10A" } } } 

Der der Antwort zugeordnete URI wird als Selbstverbindung qualifiziert . Die Semantik der Selbstbeziehung ist klar - es ist einfach der kanonische Ort, an dem auf die Ressource zugegriffen werden kann.

4.3. Bessere Links erstellen

Eine weitere sehr wichtige Abstraktion, die von der Bibliothek angeboten wird, ist der WebMvcLinkBuilder, der das Erstellen von URIs vereinfacht, indem fest codierte Links vermieden werden.

Das folgende Snippet zeigt das Erstellen des Kunden-Self-Links mithilfe der WebMvcLinkBuilder- Klasse:

linkTo(CustomerController.class).slash(customer.getCustomerId()).withSelfRel(); 

Werfen wir einen Blick:

  • Die linkTo () -Methode überprüft die Controller-Klasse und erhält ihre Root-Zuordnung
  • Die Methode slash () fügt den Wert customerId als Pfadvariable des Links hinzu
  • Schließlich qualifiziert die withSelfMethod () die Beziehung als Selbstverknüpfung

5. Beziehungen

Im vorherigen Abschnitt haben wir eine selbstreferenzierende Beziehung gezeigt. Komplexere Systeme können jedoch auch andere Beziehungen beinhalten.

Beispielsweise kann ein Kunde eine Beziehung zu Bestellungen haben. Lassen Sie uns auch die Order- Klasse als Ressource modellieren :

public class Order extends RepresentationModel { private String orderId; private double price; private int quantity; // standard getters and setters } 

An dieser Stelle können wir den CustomerController um eine Methode erweitern, die alle Bestellungen eines bestimmten Kunden zurückgibt:

@GetMapping(value = "/{customerId}/orders", produces = { "application/hal+json" }) public CollectionModel getOrdersForCustomer(@PathVariable final String customerId) { List orders = orderService.getAllOrdersForCustomer(customerId); for (final Order order : orders) { Link selfLink = linkTo(methodOn(CustomerController.class) .getOrderById(customerId, order.getOrderId())).withSelfRel(); order.add(selfLink); } Link link = linkTo(methodOn(CustomerController.class) .getOrdersForCustomer(customerId)).withSelfRel(); CollectionModel result = new CollectionModel(orders, link); return result; } 

Unsere Methode gibt ein CollectionModel- Objekt zurück, das dem HAL-Rückgabetyp entspricht, sowie einen Link " _self" für jede Bestellung und die vollständige Liste.

Hierbei ist zu beachten, dass der Hyperlink für die Kundenbestellungen von der Zuordnung der Methode getOrdersForCustomer () abhängt . Wir werden diese Arten von Links als Methodenlinks bezeichnen und zeigen, wie der WebMvcLinkBuilder bei ihrer Erstellung helfen kann.

6. Links zu Controller-Methoden

Der WebMvcLinkBuilder bietet umfassende Unterstützung für Spring MVC-Controller. Das folgende Beispiel zeigt, wie HATEOAS-Hyperlinks basierend auf der Methode getOrdersForCustomer () der CustomerController- Klasse erstellt werden:

Link ordersLink = linkTo(methodOn(CustomerController.class) .getOrdersForCustomer(customerId)).withRel("allOrders"); 

Die methodOn () erhält die Methode Zuordnung durch dummy Aufruf des Zielmethode macht auf dem Proxy - Controller und legt den customerId als Pfad Variable der URI.

7. Frühling HATEOAS in Aktion

Lassen Sie uns die Erstellung von Self-Links und Methoden-Links in einer getAllCustomers () -Methode zusammenfassen:

@GetMapping(produces = { "application/hal+json" }) public CollectionModel getAllCustomers() { List allCustomers = customerService.allCustomers(); for (Customer customer : allCustomers) { String customerId = customer.getCustomerId(); Link selfLink = linkTo(CustomerController.class).slash(customerId).withSelfRel(); customer.add(selfLink); if (orderService.getAllOrdersForCustomer(customerId).size() > 0) { Link ordersLink = linkTo(methodOn(CustomerController.class) .getOrdersForCustomer(customerId)).withRel("allOrders"); customer.add(ordersLink); } } Link link = linkTo(CustomerController.class).withSelfRel(); CollectionModel result = new CollectionModel(allCustomers, link); return result; }

Rufen Sie als Nächstes die Methode getAllCustomers () auf :

curl //localhost:8080/spring-security-rest/api/customers 

Und untersuchen Sie das Ergebnis:

{ "_embedded": { "customerList": [{ "customerId": "10A", "customerName": "Jane", "companyName": "ABC Company", "_links": { "self": { "href": "//localhost:8080/spring-security-rest/api/customers/10A" }, "allOrders": { "href": "//localhost:8080/spring-security-rest/api/customers/10A/orders" } } },{ "customerId": "20B", "customerName": "Bob", "companyName": "XYZ Company", "_links": { "self": { "href": "//localhost:8080/spring-security-rest/api/customers/20B" }, "allOrders": { "href": "//localhost:8080/spring-security-rest/api/customers/20B/orders" } } },{ "customerId": "30C", "customerName": "Tim", "companyName": "CKV Company", "_links": { "self": { "href": "//localhost:8080/spring-security-rest/api/customers/30C" } } }] }, "_links": { "self": { "href": "//localhost:8080/spring-security-rest/api/customers" } } }

Innerhalb jeder Ressourcendarstellung gibt es einen Selbstlink und den Link allOrders , um alle Bestellungen eines Kunden zu extrahieren. Wenn ein Kunde keine Bestellungen hat, wird der Link für Bestellungen nicht angezeigt.

Dieses Beispiel zeigt, wie Spring HATEOAS die API-Erkennbarkeit in einem Rest-Webdienst fördert. Wenn der Link vorhanden ist, kann der Kunde ihm folgen und alle Bestellungen für einen Kunden erhalten:

curl //localhost:8080/spring-security-rest/api/customers/10A/orders 
{ "_embedded": { "orderList": [{ "orderId": "001A", "price": 150, "quantity": 25, "_links": { "self": { "href": "//localhost:8080/spring-security-rest/api/customers/10A/001A" } } },{ "orderId": "002A", "price": 250, "quantity": 15, "_links": { "self": { "href": "//localhost:8080/spring-security-rest/api/customers/10A/002A" } } }] }, "_links": { "self": { "href": "//localhost:8080/spring-security-rest/api/customers/10A/orders" } } }

8. Fazit

In diesem Tutorial haben wir erläutert, wie Sie mithilfe des Spring HATEOAS-Projekts einen hypermediengesteuerten Spring REST-Webdienst erstellen .

Im Beispiel sehen wir, dass der Client einen einzelnen Einstiegspunkt für die Anwendung haben kann und weitere Aktionen basierend auf den Metadaten in der Antwortdarstellung ausgeführt werden können.

Dadurch kann der Server sein URI-Schema ändern, ohne den Client zu beschädigen. Außerdem kann die Anwendung neue Funktionen ankündigen, indem sie neue Links oder URIs in die Darstellung einfügt.

Die vollständige Implementierung dieses Artikels finden Sie im GitHub-Projekt.

REST unten

Ich habe gerade den neuen Learn Spring- Kurs angekündigt , der sich auf die Grundlagen von Spring 5 und Spring Boot 2 konzentriert:

>> Überprüfen Sie den Kurs