Рубрики
Без рубрики

Вступление к весеннему HATEOAS

Краткое введение в использование Spring HATEOAS для добавления гипермедиа в практический API Spring.

Автор оригинала: baeldung.

1. Обзор

В этой статье объясняется процесс создания веб-сервиса REST, управляемого гипермедиа, с использованием проекта Spring HATEOAS.

2. Весна-НЕНАВИСТЬ

Проект Spring HATEOAS – это библиотека API, которую мы можем использовать для легкого создания представлений REST, которые следуют принципу HATEOAS (Гипертекст как механизм состояния приложения).

Вообще говоря, принцип подразумевает, что API должен направлять клиента через приложение, возвращая соответствующую информацию о следующих потенциальных шагах вместе с каждым ответом.

В этой статье мы собираемся построить пример с использованием Spring HATEOAS с целью разъединения клиента и сервера и теоретически разрешить API изменять свою схему URI, не нарушая работу клиентов.

3. Подготовка

Во – первых, давайте добавим зависимость Spring HATEOAS:


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

Если мы не используем Spring Boot, мы можем добавить в наш проект следующие библиотеки:


    org.springframework.hateoas
    spring-hateoas
    0.25.1.RELEASE


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

Как всегда, мы можем искать последние версии зависимостей starter HATEOAS , spring-hateoas и spring-plugin-core в Maven Central.

Далее, у нас есть Клиент ресурс без поддержки Spring HATEOAS:

public class Customer {

    private String customerId;
    private String customerName;
    private String companyName;

    // standard getters and setters
}

И у нас есть класс контроллера без поддержки Spring HATEOAS:

@RestController
@RequestMapping(value = "/customers")
public class CustomerController {
    @Autowired
    private CustomerService customerService;

    @GetMapping("/{customerId}")
    public Customer getCustomerById(@PathVariable String customerId) {
        return customerService.getCustomerDetail(customerId);
    }
}

Наконец, представление Клиента ресурса:

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

4. Добавление поддержки HATEOAS

В проекте Spring HATEOAS нам не нужно ни искать контекст сервлета, ни связывать переменную path с базовым URI.

Вместо этого Spring HATEOAS предлагает три абстракции для создания URI – RepresentationModel, Link и WebMvcLinkBuilder . Мы можем использовать их для создания метаданных и связывания их с представлением ресурсов.

4.1. Добавление поддержки Гипермедиа на Ресурс

Проект предоставляет базовый класс с именем Модель представления для наследования при создании представления ресурсов:

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

Ресурс Customer расширяется из класса Модель представления , чтобы наследовать метод add () |. Поэтому, как только мы создадим ссылку, мы можем легко установить это значение для представления ресурса, не добавляя в него никаких новых полей.

4.2. Создание ссылок

Весенний ХАТЕОАС обеспечивает Ссылка объект для хранения метаданных (местоположение или URI ресурса).

Во – первых, мы создадим простую ссылку вручную:

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

Объект Link следует синтаксису Atom link и состоит из результата , который идентифицирует отношение к ресурсу и href атрибута, который является самой фактической ссылкой.

Вот как выглядит ресурс Customer теперь, когда он содержит новую ссылку:

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

URI, связанный с ответом, квалифицируется как ссылка self . Семантика отношения self ясна – это просто каноническое местоположение, в котором можно получить доступ к ресурсу.

4.3. Создание Лучших Ссылок

Еще одной очень важной абстракцией, предлагаемой библиотекой, является | WebMvcLinkBuilder , которая упрощает создание URI , избегая жестко закодированных ссылок.

В следующем фрагменте показано построение самосвязи клиента с помощью класса WebMvcLinkBuilder :

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

Давайте посмотрим:

  • метод linkTo() проверяет класс контроллера и получает его корневое сопоставление
  • метод slash() добавляет значение CustomerID в качестве переменной пути ссылки
  • наконец, метод with Self() квалифицирует отношение как самосвязь

5. Отношения

В предыдущем разделе мы показали отношение самореференции. Однако более сложные системы могут включать и другие отношения.

Например, клиент может иметь связь с заказами. Давайте также смоделируем класс Order в качестве ресурса:

public class Order extends RepresentationModel {
    private String orderId;
    private double price;
    private int quantity;

    // standard getters and setters
}

На этом этапе мы можем расширить CustomerController с помощью метода, который возвращает все заказы конкретного клиента:

@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 = CollectionModel.of(orders, link);
    return result;
}

Наш метод возвращает Модель коллекции объект, соответствующий типу возврата СПРАВКИ, а также ссылку ” _self” для каждого из заказов и полного списка.

Здесь важно отметить, что гиперссылка для заказов клиентов зависит от сопоставления метода getOrdersForCustomer () . Мы будем называть эти типы ссылок ссылками на методы и покажем, как WebMvcLinkBuilder может помочь в их создании.

6. Ссылки на методы контроллера

Web Mvc LinkBuilder предлагает богатую поддержку контроллеров Spring MVC. В следующем примере показано, как создать гиперссылки HATEOAS на основе метода getOrdersForCustomer() класса CustomerController :

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

Метод () получает сопоставление методов путем фиктивного вызова целевого метода на контроллере прокси-сервера и устанавливает CustomerID в качестве переменной пути URI.

7. Весенняя НЕНАВИСТЬ в действии

Давайте объединим самосвязь и создание ссылок на методы в getAllCustomers() метод:

@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 = CollectionModel.of(allCustomers, link);
    return result;
}

Далее, давайте вызовем метод getAllCustomers() :

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

И изучите результат:

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

В каждом представлении ресурса есть ссылка self и ссылка all Orders для извлечения всех заказов клиента. Если у клиента нет заказов, ссылка для заказов не появится.

Этот пример демонстрирует, как Spring HATEOAS способствует обнаружению API в веб-службе rest. Если ссылка существует, клиент может перейти по ней и получить все заказы для клиента:

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

8. Заключение

В этом уроке мы обсудили, как создать веб-сервис Spring REST, управляемый гипермедиа, с помощью проекта Spring HATEOAS .

В примере мы видим, что у клиента может быть одна точка входа в приложение, и дальнейшие действия могут быть предприняты на основе метаданных в представлении ответа.

Это позволяет серверу изменять свою схему URI, не нарушая работу клиента. Кроме того, приложение может рекламировать новые возможности, помещая новые ссылки или URL-адреса в представление.

Наконец, полную реализацию этой статьи можно найти в проекте GitHub .