# Spring HATEOAS - Reference Documentation ## 1. Preface ### 1.1. Migrating to Spring HATEOAS 1.0 For 1.0 we took the chance to re-evaluate some of the design and package structure choices we had made for the 0.x branch. There had been an incredible amount of feedback on it and the major version bump seemed to be the most natural place to refactor those. #### 1.1.1. The changes The biggest changes in package structure were driven by the introduction of a hypermedia type registration API to support additional media types in Spring HATEOAS. This lead to the clear separation of client and server APIs (packages named respectively) as well as media type implementations in the package `mediatype`. The easiest way to get your code base upgraded to the new API is by using the [migration script](#migrate-to-1.0.script). Before we jump to that, here are the changes at a quick glance. ##### Representation models The `ResourceSupport`/`Resource`/`Resources`/`PagedResources` group of classes never really felt appropriately named. After all, these types do not actually manifest resources but rather representation models that can be enriched with hypermedia information and affordances. Here’s how new names map to the old ones: * `ResourceSupport` is now `RepresentationModel` * `Resource` is now `EntityModel` * `Resources` is now `CollectionModel` * `PagedResources` is now `PagedModel` Consequently, `ResourceAssembler` has been renamed to `RepresentationModelAssembler` and its methods `toResource(…)` and `toResources(…)` have been renamed to `toModel(…)` and `toCollectionModel(…)` respectively. Also the name changes have been reflected in the classes contained in `TypeReferences`. * `RepresentationModel.getLinks()` now exposes a `Links` instance (over a `List`) as that exposes additional API to concatenate and merge different `Links` instances using various strategies. Also it has been turned into a self-bound generic type to allow the methods that add links to the instance return the instance itself. * The `LinkDiscoverer` API has been moved to the `client` package. * The `LinkBuilder` and `EntityLinks` APIs have been moved to the `server` package. * `ControllerLinkBuilder` has been moved into `server.mvc` and deprecated to be replaced by `WebMvcLinkBuilder`. * `RelProvider` has been renamed to `LinkRelationProvider` and returns `LinkRelation` instances instead of `String`s. * `VndError` has been moved to the `mediatype.vnderror` package. #### 1.1.2. The migration script You can find [a script](https://github.com/spring-projects/spring-hateoas/tree/master/etc) to run from your application root that will update all import statements and static method references to Spring HATEOAS types that moved in our source code repository. Simply download that, run it from your project root. By default it will inspect all Java source files and replace the legacy Spring HATEOAS type references with the new ones. Example 1. Sample application of the migration script ``` $ ./migrate-to-1.0.sh Migrating Spring HATEOAS references to 1.0 for files : *.java Adapting ./src/main/java/… … Done! ``` Note that the script will not necessarily be able to entirely fix all changes, but it should cover the most important refactorings. Now verify the changes made to the files in your favorite Git client and commit as appropriate. In case you find method or type references unmigrated, please open a ticket in out issue tracker. #### 1.1.3. Migrating from 1.0 M3 to 1.0 RC1 * `Link.andAffordance(…)` taking Affordance details have been moved to `Affordances`. To manually build up `Affordance` instances now use `Affordances.of(link).afford(…)`. Also note the new `AffordanceBuilder` type exposed from `Affordances` for fluent usage. See [Affordances](#server.affordances) for details. * `AffordanceModelFactory.getAffordanceModel(…)` now receives `InputPayloadMetadata` and `PayloadMetadata` instances instead of `ResolvableType`s to allow non-type-based implementations. Custom media type implementations have to be adapted to that accordingly. * HAL Forms now does not render property attributes if their value adheres to what’s defined as default in the spec. I.e. if previously `required` was explicitly set to `false`, we now just omit the entry for `required`. We also now only force them to be non-required for templates that use `PATCH` as the HTTP method. ## 2. Fundamentals This section covers the basics of Spring HATEOAS and its fundamental domain abstractions. ### 2.1. Links The fundamental idea of hypermedia is to enrich the representation of a resource with hypermedia elements. The simplest form of that are links. They indicate a client that it can navigate to a certain resource. The semantics of a related resource are defined in a so-called link relation. You might have seen this in the header of an HTML file already: Example 2. A link in an HTML document ``` ``` As you can see the link points to a resource `theme.css` and indicates that it is a style sheet. Links often carry additional information, like the media type that the resource pointed to will return. However, the fundamental building blocks of a link are its reference and relation. Spring HATEOAS lets you work with links through its immutable `Link` value type. Its constructor takes both a hypertext reference and a link relation, the latter being defaulted to the IANA link relation `self`. Read more on the latter in [Link relations](#fundamentals.link-relations). Example 3. Using links ``` Link link = Link.of("/something"); assertThat(link.getHref()).isEqualTo("/something"); assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF); link = Link.of("/something", "my-rel"); assertThat(link.getHref()).isEqualTo("/something"); assertThat(link.getRel()).isEqualTo(LinkRelation.of("my-rel")); ``` `Link` exposes other attributes as defined in [RFC-8288](https://tools.ietf.org/html/rfc8288). You can set them by calling the corresponding wither method on a `Link` instance. Find more information on how to create links pointing to Spring MVC and Spring WebFlux controllers in [ Building links in Spring MVC](#server.link-builder.webmvc) and [Building links in Spring WebFlux](#server.link-builder.webflux). ### 2.2. URI templates For a Spring HATEOAS `Link`, the hypertext reference can not only be a URI, but also a URI template according to [RFC-6570](https://tools.ietf.org/html/rfc6570). A URI template contains so-called template variables and allows expansion of these parameters. This allows clients to turn parameterized templates into URIs without having to know about the structure of the final URI, it only needs to know about the names of the variables. Example 4. Using links with templated URIs ``` Link link = Link.of("/{segment}/something{?parameter}"); assertThat(link.isTemplated()).isTrue(); (1) assertThat(link.getVariableNames()).contains("segment", "parameter"); (2) Map values = new HashMap<>(); values.put("segment", "path"); values.put("parameter", 42); assertThat(link.expand(values).getHref()) (3) .isEqualTo("/path/something?parameter=42"); ``` |**1**|The `Link` instance indicates that is templated, i.e. it contains a URI template.| |-----|---------------------------------------------------------------------------------| |**2**| It exposes the parameters contained in the template. | |**3**| It allows expansion of the parameters. | URI templates can be constructed manually and template variables added later on. Example 5. Working with URI templates ``` UriTemplate template = UriTemplate.of("/{segment}/something") .with(new TemplateVariable("parameter", VariableType.REQUEST_PARAM); assertThat(template.toString()).isEqualTo("/{segment}/something{?parameter}"); ``` ### 2.3. Link relations To indicate the relationship of the target resource to the current one so-called link relations are used. Spring HATEOAS provides a `LinkRelation` type to easily create `String`-based instances of it. #### 2.3.1. IANA link relations The Internet Assigned Numbers Authority contains a set of [predefined link relations](https://www.iana.org/assignments/link-relations/link-relations.xhtml). They can be referred to via `IanaLinkRelations`. Example 6. Using IANA link relations ``` Link link = Link.of("/some-resource"), IanaLinkRelations.NEXT); assertThat(link.getRel()).isEqualTo(LinkRelation.of("next")); assertThat(IanaLinkRelation.isIanaRel(link.getRel())).isTrue(); ``` ### Representation models To easily create hypermedia enriched representations, Spring HATEOAS provides a set of classes with `RepresentationModel` at their root. It’s basically a container for a collection of `Link`s and has convenient methods to add those to the model. The models can later be rendered into various media type formats that will define how the hypermedia elements look in the representation. For more information on this, have a look at [Media types](#mediatypes). Example 7. The `RepresentationModel` class hierarchy diagram classes The default way to work with a `RepresentationModel` is to create a subclass of it to contain all the properties the representation is supposed to contain, create instances of that class, populate the properties and enrich it with links. Example 8. A sample representation model type ``` class PersonModel extends RepresentationModel { String firstname, lastname; } ``` The generic self-typing is necessary to let `RepresentationModel.add(…)` return instances of itself. The model type can now be used like this: Example 9. Using the person representation model ``` PersonModel model = new PersonModel(); model.firstname = "Dave"; model.lastname = "Matthews"; model.add(Link.of("https://myhost/people/42")); ``` If you returned such an instance from a Spring MVC or WebFlux controller and the client sent an `Accept` header set to `application/hal+json`, the response would look as follows: Example 10. The HAL representation generated for the person representation model ``` { "_links" : { "self" : { "href" : "https://myhost/people/42" } }, "firstname" : "Dave", "lastname" : "Matthews" } ``` #### 2.4.1. Item resource representation model For a resource that’s backed by a singular object or concept, a convenience `EntityModel` type exists. Instead of creating a custom model type for each concept, you can just reuse an already existing type and wrap instances of it into the `EntityModel`. Example 11. Using `EntityModel` to wrap existing objects ``` Person person = new Person("Dave", "Matthews"); EntityModel model = EntityModel.of(person); ``` #### 2.4.2. Collection resource representation model For resources that are conceptually collections, a `CollectionModel` is available. Its elements can either be simple objects or `RepresentationModel` instances in turn. Example 12. Using `CollectionModel` to wrap a collection of existing objects ``` Collection people = Collections.singleton(new Person("Dave", "Matthews")); CollectionModel model = CollectionModel.of(people); ``` ## 3. Server-side support ### Building links in Spring MVC Now we have the domain vocabulary in place, but the main challenge remains: how to create the actual URIs to be wrapped into `Link` instances in a less fragile way. Right now, we would have to duplicate URI strings all over the place. Doing so is brittle and unmaintainable. Assume you have your Spring MVC controllers implemented as follows: ``` @Controller class PersonController { @GetMapping("/people") HttpEntity showAll() { … } @GetMapping(value = "/{person}", method = RequestMethod.GET) HttpEntity show(@PathVariable Long person) { … } } ``` We see two conventions here. The first is a collection resource that is exposed through `@GetMapping` annotation of the controller method, with individual elements of that collection exposed as direct sub resources. The collection resource might be exposed at a simple URI (as just shown) or more complex ones (such as `/people/{id}/addresses`). Suppose you would like to link to the collection resource of all people. Following the approach from above would cause two problems: * To create an absolute URI, you would need to look up the protocol, hostname, port, servlet base, and other values. This is cumbersome and requires ugly manual string concatenation code. * You probably do not want to concatenate the `/people` on top of your base URI, because you would then have to maintain the information in multiple places. If you change the mapping, you then have to change all the clients pointing to it. Spring HATEOAS now provides a `WebMvcLinkBuilder` that lets you create links by pointing to controller classes. The following example shows how to do so: ``` import static org.sfw.hateoas.server.mvc.WebMvcLinkBuilder.*; Link link = linkTo(PersonController.class).withRel("people"); assertThat(link.getRel()).isEqualTo(LinkRelation.of("people")); assertThat(link.getHref()).endsWith("/people"); ``` The `WebMvcLinkBuilder` uses Spring’s `ServletUriComponentsBuilder` under the hood to obtain the basic URI information from the current request. Assuming your application runs at `[localhost:8080/your-app](http://localhost:8080/your-app)`, this is exactly the URI on top of which you are constructing additional parts. The builder now inspects the given controller class for its root mapping and thus ends up with `[localhost:8080/your-app/people](http://localhost:8080/your-app/people)`. You can also build more nested links as well. The following example shows how to do so: ``` Person person = new Person(1L, "Dave", "Matthews"); // /person / 1 Link link = linkTo(PersonController.class).slash(person.getId()).withSelfRel(); assertThat(link.getRel(), is(IanaLinkRelation.SELF.value())); assertThat(link.getHref(), endsWith("/people/1")); ``` The builder also allows creating URI instances to build up (for example, response header values): ``` HttpHeaders headers = new HttpHeaders(); headers.setLocation(linkTo(PersonController.class).slash(person).toUri()); return new ResponseEntity(headers, HttpStatus.CREATED); ``` #### 3.1.1. Building links that point to methods You can even build links that point to methods or create dummy controller method invocations. The first approach is to hand a `Method` instance to the `WebMvcLinkBuilder`. The following example shows how to do so: ``` Method method = PersonController.class.getMethod("show", Long.class); Link link = linkTo(method, 2L).withSelfRel(); assertThat(link.getHref()).endsWith("/people/2")); ``` This is still a bit dissatisfying, as we have to first get a `Method` instance, which throws an exception and is generally quite cumbersome. At least we do not repeat the mapping. An even better approach is to have a dummy method invocation of the target method on a controller proxy, which we can create by using the `methodOn(…)` helper. The following example shows how to do so: ``` Link link = linkTo(methodOn(PersonController.class).show(2L)).withSelfRel(); assertThat(link.getHref()).endsWith("/people/2"); ``` `methodOn(…)` creates a proxy of the controller class that records the method invocation and exposes it in a proxy created for the return type of the method. This allows the fluent expression of the method for which we want to obtain the mapping. However, there are a few constraints on the methods that can be obtained by using this technique: * The return type has to be capable of proxying, as we need to expose the method invocation on it. * The parameters handed into the methods are generally neglected (except the ones referred to through `@PathVariable`, because they make up the URI). ### 3.2. Building links in Spring WebFlux TODO ### 3.3. Affordances > > > > > The affordances of the environment are what it offers …​ what it provides or furnishes, either for good or ill. The verb 'to afford' is found in the dictionary, but the noun 'affordance' is not. I have made it up. > > > > — James J. Gibson > The Ecological Approach to Visual Perception (page 126) REST-based resources provide not just data but controls. The last ingredient to form a flexible service are detailed **affordances** on how to use the various controls. Because affordances are associated with links, Spring HATEOAS provides an API to attach as many related methods as needed to a link. Just as you can create links by pointing to Spring MVC controller methods (see [ Building links in Spring MVC](#server.link-builder.webmvc) for details) you …​ The following code shows how to take a **self** link and associate two more affordances: Example 13. Connecting affordances to `GET /employees/{id}` ``` @GetMapping("/employees/{id}") public EntityModel findOne(@PathVariable Integer id) { Class controllerClass = EmployeeController.class; // Start the affordance with the "self" link, i.e. this method. Link findOneLink = linkTo(methodOn(controllerClass).findOne(id)).withSelfRel(); (1) // Return the affordance + a link back to the entire collection resource. return EntityModel.of(EMPLOYEES.get(id), // findOneLink // .andAffordance(afford(methodOn(controllerClass).updateEmployee(null, id))) (2) .andAffordance(afford(methodOn(controllerClass).partiallyUpdateEmployee(null, id)))); (3) } ``` |**1**| Create the **self** link. | |-----|--------------------------------------------------------------------| |**2**| Associate the `updateEmployee` method with the `self` link. | |**3**|Associate the `partiallyUpdateEmployee` method with the `self` link.| Using `.andAffordance(afford(…​))`, you can use the controller’s methods to connect a `PUT` and a `PATCH` operation to a `GET` operation. Imagine that the related methods **afforded** above look like this: Example 14. `updateEmpoyee` method that responds to `PUT /employees/{id}` ``` @PutMapping("/employees/{id}") public ResponseEntity updateEmployee( // @RequestBody EntityModel employee, @PathVariable Integer id) ``` Example 15. `partiallyUpdateEmployee` method that responds to `PATCH /employees/{id}` ``` @PatchMapping("/employees/{id}") public ResponseEntity partiallyUpdateEmployee( // @RequestBody EntityModel employee, @PathVariable Integer id) ``` Pointing to those methods using the `afford(…)` methods will cause Spring HATEOAS to analyze the request body and response types and capture metadata to allow different media type implementations to use that information to translate that into descriptions of the input and outputs. #### 3.3.1. Building affordances manually While the primary way to register affordances for a link, it might be necessary to build some of them manually. This can be achieved by using the `Affordances` API: Example 16. Using the `Affordances` API to manually register affordances ``` var methodInvocation = methodOn(EmployeeController.class).all(); var link = Affordances.of(linkTo(methodInvocation).withSelfRel()) (1) .afford(HttpMethod.POST) (2) .withInputAndOutput(Employee.class) // .withName("createEmployee") // .andAfford(HttpMethod.GET) (3) .withOutput(Employee.class) // .addParameters(// QueryParameter.optional("name"), // QueryParameter.optional("role")) // .withName("search") // .toLink(); ``` |**1**| You start by creating an instance of `Affordances` from a `Link` instance creating the context for describing the affordances. | |-----|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |**2**|Each affordance starts with the HTTP method it’s supposed to support. We then register a type as payload description and name the affordance explicitly. The latter can be omitted and a default name will be derived from the HTTP method and input type name. This effectively creates the same affordance as the pointer to `EmployeeController.newEmployee(…)` created.| |**3**| The next affordance is built to reflect what’s happening for the pointer to `EmployeeController.search(…)`. Here we define `Employee` to be the model for the response created and explicitly register `QueryParameter`s. | Affordances are backed by media type specific affordance models that translate the general affordance metadata into specific representations. Please make sure to check the section on affordances in the [Media types](#mediatypes) section to find more details about how to control the exposure of that metadata. ### 3.4. Forwarded header handling [RFC-7239 forwarding headers](https://tools.ietf.org/html/rfc7239) are most commonly used when your application is behind a proxy, behind a load balancer, or in the cloud. The node that actually receives the web request is part of the infrastructure, and *forwards* the request to your application. Your application may be running on `localhost:8080`, but to the outside world you’re expected to be at `reallycoolsite.com` (and on the web’s standard port 80). By having the proxy include extra headers (which many already do), Spring HATEOAS can generate links properly as it uses Spring Framework functionality to obtain the base URI of the original request. | |Anything that can change the root URI based on external inputs must be properly guarded.
That’s why, by default, forwarded header handling is **disabled**.
You MUST enable it to be operational.
If you are deploying to the cloud or into a configuration where you control the proxies and load balancers, then you’ll certainly want to use this feature.| |---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| To enable forwarded header handling you need to register Spring’s `ForwardedHeaderFilter` for Spring MVC (details [here](https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#filters-forwarded-headers)) or `ForwardedHeaderTransformer` for Spring WebFlux (details [here](https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-forwarded-headers)) in your application. In a Spring Boot application those components can be simply declared as Spring beans as described [here](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-embedded-container-servlets-filters-listeners-beans). Example 17. Registering a `ForwardedHeaderFilter` ``` @Bean ForwardedHeaderFilter forwardedHeaderFilter() { return new ForwardedHeaderFilter(); } ``` This will create a servlet filter that processes all the `X-Forwarded-…` headers. And it will register it properly with the servlet handlers. For a Spring WebFlux application, the reactive counterpart is `ForwardedHeaderTransformer`: Example 18. Registering a `ForwardedHeaderTransformer` ``` @Bean ForwardedHeaderTransformer forwardedHeaderTransformer() { return new ForwardedHeaderTransformer(); } ``` This will create a function that transforms reactive web requests, processing `X-Forwarded-…` headers. And it will register it properly with WebFlux. With configuration as shown above in place, a request passing `X-Forwarded-…` headers will see those reflected in the links generated: Example 19. A request using `X-Forwarded-…` headers ``` curl -v localhost:8080/employees \ -H 'X-Forwarded-Proto: https' \ -H 'X-Forwarded-Host: example.com' \ -H 'X-Forwarded-Port: 9001' ``` Example 20. The corresponding response with the links generated to consider those headers ``` { "_embedded": { "employees": [ { "id": 1, "name": "Bilbo Baggins", "role": "burglar", "_links": { "self": { "href": "https://example.com:9001/employees/1" }, "employees": { "href": "https://example.com:9001/employees" } } } ] }, "_links": { "self": { "href": "https://example.com:9001/employees" }, "root": { "href": "https://example.com:9001" } } } ``` ### Using the EntityLinks interface | |`EntityLinks` and its various implementations are NOT currently provided out-of-the-box for Spring WebFlux applications.
The contract defined in the `EntityLinks` SPI was originally aimed at Spring Web MVC and doesn’t consider Reactor types.
Developing a comparable contract that supports reactive programming is still in progress.| |---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| So far, we have created links by pointing to the web framework implementations (that is, the Spring MVC controllers) and inspected the mapping. In many cases, these classes essentially read and write representations backed by a model class. The `EntityLinks` interface now exposes an API to look up a `Link` or `LinkBuilder` based on the model types. The methods essentially return links that point either to the collection resource (such as `/people`) or to an item resource (such as `/people/1`). The following example shows how to use `EntityLinks`: ``` EntityLinks links = …; LinkBuilder builder = links.linkFor(Customer.class); Link link = links.linkToItemResource(Customer.class, 1L); ``` `EntityLinks` is available via dependency injection by activating `@EnableHypermediaSupport` in your Spring MVC configuration. This will cause a variety of default implementations of `EntityLinks` being registered. The most fundamental one is `ControllerEntityLinks` that inspects SpringMVC controller classes. If you want to register your own implementation of `EntityLinks`, check out [this section](#server.entity-links.spi). #### 3.5.1. EntityLinks based on Spring MVC controllers Activating entity links functionality causes all the Spring MVC controllers available in the current `ApplicationContext` to be inspected for the `@ExposesResourceFor(…)` annotation. The annotation exposes which model type the controller manages. Beyond that, we assume that you adhere to the following URI mapping setup and conventions: * A type level `@ExposesResourceFor(…)` declaring which entity type the controller exposes collection and item resources for. * A class level base mapping that represents the collection resource. * An additional method level mapping that extends the mapping to append an identifier as additional path segment. The following example shows an implementation of an `EntityLinks`-capable controller: ``` @Controller @ExposesResourceFor(Order.class) (1) @RequestMapping("/orders") (2) class OrderController { @GetMapping (3) ResponseEntity orders(…) { … } @GetMapping("{id}") (4) ResponseEntity order(@PathVariable("id") … ) { … } } ``` |**1**| The controller indicates it’s exposing collection and item resources for the entity `Order`. | |-----|------------------------------------------------------------------------------------------------------------------------------------------| |**2**| Its collection resource is exposed under `/orders` | |**3**| That collection resource can handle `GET` requests. Add more methods for other HTTP methods at your convenience. | |**4**|An additional controller method to handle a subordinate resource taking a path variable to expose an item resource, i.e. a single `Order`.| With this in place, when you enable `EntityLinks` `@EnableHypermediaSupport` in your Spring MVC configuration, you can create links to the controller as follows: ``` @Controller class PaymentController { private final EntityLinks entityLinks; PaymentController(EntityLinks entityLinks) { (1) this.entityLinks = entityLinks; } @PutMapping(…) ResponseEntity payment(@PathVariable Long orderId) { Link link = entityLinks.linkToItemResource(Order.class, orderId); (2) … } } ``` |**1**|Inject `EntityLinks` made available by `@EnableHypermediaSupport` in your configuration.| |-----|----------------------------------------------------------------------------------------| |**2**| Use the APIs to build links by using the entity types instead of controller classes. | As you can see, you can refer to resources managing `Order` instances without referring to `OrderController` explicitly. #### 3.5.2. EntityLinks API in detail Fundamentally, `EntityLinks` allows to build `LinkBuilder`s and `Link` instances to collection and item resources of an entity type. Methods starting with `linkFor…` will produce `LinkBuilder` instances for you to extend and augment with additional path segments, parameters, etc. Methods starting with `linkTo` produce fully prepared `Link` instances. While for collection resources providing an entity type is sufficient, links to item resources will need an identifier provided. This usually looks like this: Example 21. Obtaining a link to an item resource ``` entityLinks.linkToItemResource(order, order.getId()); ``` If you find yourself repeating those method calls the identifier extraction step can be pulled out into a reusable `Function` to be reused throughout different invocations: ``` Function idExtractor = Order::getId; (1) entityLinks.linkToItemResource(order, idExtractor); (2) ``` |**1**|The identifier extraction is externalized so that it can be held in a field or constant.| |-----|----------------------------------------------------------------------------------------| |**2**| The link lookup using the extractor. | ##### TypedEntityLinks As controller implementations are often grouped around entity types, you’ll very often find yourself using the same extractor function (see [EntityLinks API in detail](#server.entity-links.api) for details) all over the controller class. We can centralize the identifier extraction logic even more by obtaining a `TypedEntityLinks` instance providing the extractor once, so that the actual lookups don’t have to deal with the extraction anymore at all. Example 22. Using TypedEntityLinks ``` class OrderController { private final TypedEntityLinks links; OrderController(EntityLinks entityLinks) { (1) this.links = entityLinks.forType(Order::getId); (2) } @GetMapping ResponseEntity someMethod(…) { Order order = … // lookup order Link link = links.linkToItemResource(order); (3) } } ``` |**1**| Inject an `EntityLinks` instance. | |-----|------------------------------------------------------------------------------------------------| |**2**|Indicate you’re going to look up `Order` instances with a certain identifier extractor function.| |**3**| Look up item resource links based on a sole `Order` instance. | #### 3.5.3. EntityLinks as SPI The `EntityLinks` instance created by `@EnableHypermediaSupport` is of type `DelegatingEntityLinks` which will in turn pick up all other `EntityLinks` implementations available as beans in the `ApplicationContext`. It’s registered as primary bean so that it’s always the sole injection candidate when you inject `EntityLinks` in general.`ControllerEntityLinks` is the default implementation that will be included in the setup, but users are free to implement and register their own implementations. Making those available to the `EntityLinks` instance available for injection is a matter of registering your implementation as Spring bean. Example 23. Declaring a custom EntityLinks implementation ``` @Configuration class CustomEntityLinksConfiguration { @Bean MyEntityLinks myEntityLinks(…) { return new MyEntityLinks(…); } } ``` An example for the extensibility of this mechanism is Spring Data REST’s [`RepositoryEntityLinks`](https://github.com/spring-projects/spring-data-rest/blob/3a0cba94a2cc8739375ecf24086da2f7c3bbf038/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryEntityLinks.java), which uses the repository mapping information to create links pointing to resources backed by Spring Data repositories. At the same time, it even exposes additional lookup methods for other types of resources. If you want to make use of these, simply inject `RepositoryEntityLinks` explicitly. ### Representation model assembler As the mapping from an entity to a representation model must be used in multiple places, it makes sense to create a dedicated class responsible for doing so. The conversion contains very custom steps but also a few boilerplate steps: 1. Instantiation of the model class 2. Adding a link with a `rel` of `self` pointing to the resource that gets rendered. Spring HATEOAS now provides a `RepresentationModelAssemblerSupport` base class that helps reduce the amount of code you need to write. The following example shows how to use it: ``` class PersonModelAssembler extends RepresentationModelAssemblerSupport { public PersonModelAssembler() { super(PersonController.class, PersonModel.class); } @Override public PersonModel toModel(Person person) { PersonModel resource = createResource(person); // … do further mapping return resource; } } ``` | |`createResource(…​)` is code you write to instantiate a `PersonModel` object given a `Person` object. It should only focus on setting attributes, not populating `Links`.| |---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------| Setting the class up as we did in the preceding example gives you the following benefits: * There are a handful of `createModelWithId(…)` methods that let you create an instance of the resource and have a `Link` with a rel of `self` added to it. The href of that link is determined by the configured controller’s request mapping plus the ID of the entity (for example, `/people/1`). * The resource type gets instantiated by reflection and expects a no-arg constructor. If you want to use a dedicated constructor or avoid the reflection performance overhead, you can override `instantiateModel(…)`. You can then use the assembler to either assemble a `RepresentationModel` or a `CollectionModel`. The following example creates a `CollectionModel` of `PersonModel` instances: ``` Person person = new Person(…); Iterable people = Collections.singletonList(person); PersonModelAssembler assembler = new PersonModelAssembler(); PersonModel model = assembler.toModel(person); CollectionModel model = assembler.toCollectionModel(people); ``` ### 3.7. Representation Model Processors Sometimes you need to tweak and adjust hypermedia representations after they have been [assembled](#server.representation-model-assembler). A perfect example is when you have a controller that deals with order fulfillment, but you need to add links related to making payments. Imagine having your ordering system producing this type of hypermedia: ``` { "orderId" : "42", "state" : "AWAITING_PAYMENT", "_links" : { "self" : { "href" : "http://localhost/orders/999" } } } ``` You wish to add a link so the client can make payment, but don’t want to mix details about your `PaymentController` into the `OrderController`. Instead of polluting the details of your ordering system, you can write a `RepresentationModelProcessor` like this: ``` public class PaymentProcessor implements RepresentationModelProcessor> { (1) @Override public EntityModel process(EntityModel model) { model.add( (2) Link.of("/payments/{orderId}").withRel(LinkRelation.of("payments")) // .expand(model.getContent().getOrderId())); return model; (3) } } ``` |**1**| This processor will only be applied to `EntityModel` objects. | |-----|-------------------------------------------------------------------------------| |**2**| Manipulate the existing `EntityModel` object by adding an unconditional link. | |**3**|Return the `EntityModel` so it can be serialized into the requested media type.| Register the processor with your application: ``` @Configuration public class PaymentProcessingApp { @Bean PaymentProcessor paymentProcessor() { return new PaymentProcessor(); } } ``` Now when you issue a hypermedia respresentation of an `Order`, the client receives this: ``` { "orderId" : "42", "state" : "AWAITING_PAYMENT", "_links" : { "self" : { "href" : "http://localhost/orders/999" }, "payments" : { (1) "href" : "/payments/42" (2) } } } ``` |**1**|You see the `LinkRelation.of("payments")` plugged in as this link’s relation.| |-----|-----------------------------------------------------------------------------| |**2**| The URI was provided by the processor. | This example is quite simple, but you can easily: * Use `WebMvcLinkBuilder` or `WebFluxLinkBuilder` to construct a dynamic link to your `PaymentController`. * Inject any services needed to conditionally add other links (e.g. `cancel`, `amend`) that are driven by state. * Leverage cross cutting services like Spring Security to add, remove, or revise links based upon the current user’s context. Also, in this example, the `PaymentProcessor` alters the provided `EntityModel`. You also have the power to*replace* it with another object. Just be advised the API requires the return type to equal the input type. ### Using the `LinkRelationProvider` API When building links, you usually need to determine the relation type to be used for the link. In most cases, the relation type is directly associated with a (domain) type. We encapsulate the detailed algorithm to look up the relation types behind a `LinkRelationProvider` API that lets you determine the relation types for single and collection resources. The algorithm for looking up the relation type follows: 1. If the type is annotated with `@Relation`, we use the values configured in the annotation. 2. If not, we default to the uncapitalized simple class name plus an appended `List` for the collection `rel`. 3. If the [EVO inflector](https://github.com/atteo/evo-inflector) JAR is in the classpath, we use the plural of the single resource `rel` provided by the pluralizing algorithm. 4. `@Controller` classes annotated with `@ExposesResourceFor` (see [ Using the EntityLinks interface](#server.entity-links) for details) transparently look up the relation types for the type configured in the annotation, so that you can use `LinkRelationProvider.getItemResourceRelFor(MyController.class)` and get the relation type of the domain type exposed. A `LinkRelationProvider` is automatically exposed as a Spring bean when you use `@EnableHypermediaSupport`. You can plug in custom providers by implementing the interface and exposing them as Spring beans in turn. ## 4. Media types ### 4.1. HAL – Hypertext Application Language [JSON Hypertext Application Language](https://tools.ietf.org/html/draft-kelly-json-hal-08) or HAL is one of the simplest and most widely adopted hypermedia media types adopted when not discussing specific web stacks. It was the first spec-based media type adopted by Spring HATEOAS. #### 4.1.1. Building HAL representation models As of Spring HATEOAS 1.1, we ship a dedicated `HalModelBuilder` that allows to create `RepresentationModel` instances through a HAL-idiomatic API. These are its fundamental assumptions: 1. A HAL representation can be backed by an arbitrary object (an entity) that builds up the domain fields contained in the representation. 2. The representation can be enriched by a variety of embedded documents, which can be either arbitrary objects or HAL representations themselves (i.e. containing nested embeddeds and links). 3. Certain HAL specific patterns (e.g. previews) can be directly used in the API so that the code setting up the representation reads like you’d describe a HAL representation following those idioms. Here’s an example of the API used: ``` // An order var order = new Order(…); (1) // The customer who placed the order var customer = customer.findById(order.getCustomerId()); var customerLink = Link.of("/orders/{id}/customer") (2) .expand(order.getId()) .withRel("customer"); var additional = … var model = HalModelBuilder.halModelOf(order) .preview(new CustomerSummary(customer)) (3) .forLink(customerLink) (4) .embed(additional) (5) .link(Link.of(…, IanaLinkRelations.SELF)); .build(); ``` |**1**| We set up some domain type. In this case, an order that has a relationship to the customer that placed it. | |-----|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |**2**| We prepare a link pointing to a resource that will expose customer details | |**3**| We start building a preview by providing the payload that’s supposed to be rendered inside the `_embeddable` clause. | |**4**| We conclude that preview by providing the target link. It transparently gets added to the `_links` object and its link relation is used as the key for the object provided in the previous step. | |**5**|Other objects can be added to show up under `_embedded`.
The key under which they’re listed is derived from the objects relation settings. They’re customizable via `@Relation` or a dedicated `LinkRelationProvider` (see [ Using the `LinkRelationProvider` API](#server.rel-provider) for details).| ``` { "_links" : { "self" : { "href" : "…" }, (1) "customer" : { "href" : "/orders/4711/customer" } (2) }, "_embedded" : { "customer" : { … }, (3) "additional" : { … } (4) } } ``` |**1**| The `self` link as explicitly provided. | |-----|--------------------------------------------------------------------------| |**2**|The `customer` link transparently added through `….preview(…).forLink(…)`.| |**3**| The preview object provided. | |**4**| Additional elements added via explicit `….embed(…)`. | In HAL `_embedded` is also used to represent top collections. They’re usually grouped under the link relation derived from the object’s type. I.e. a list of orders would look like this in HAL: ``` { "_embedded" : { "orders : [ … (1) ] } } ``` |**1**|Individual order documents go here.| |-----|-----------------------------------| Creating such a representation is as easy as this: ``` Collection orders = …; HalModelBuilder.emptyHalDocument() .embed(orders); ``` That said, if the order is empty, there’s no way to derive the link relation to appear inside `_embedded`, so that the document will stay empty if the collection is empty. If you prefer to explicitly communicate an empty collection, a type can be handed into the overload of the `….embed(…)` method taking a `Collection`. If the collection handed into the method is empty, this will cause a field rendered with its link relation derived from the given type. ``` HalModelBuilder.emptyHalModel() .embed(Collections.emptyList(), Order.class); // or .embed(Collections.emptyList(), LinkRelation.of("orders")); ``` will create the following, more explicit representation. ``` { "_embedded" : { "orders" : [] } } ``` #### 4.1.2. Configuring link rendering In HAL, the `_links` entry is a JSON object. The property names are [link relations](#fundamentals.link-relations) and each value is either [a link object or an array of link objects](https://tools.ietf.org/html/draft-kelly-json-hal-07#section-4.1.1). For a given link relation that has two or more links, the spec is clear on representation: Example 24. HAL document with two links associated with one relation ``` { "_links": { "item": [ { "href": "https://myhost/cart/42" }, { "href": "https://myhost/inventory/12" } ] }, "customer": "Dave Matthews" } ``` But if there is only one link for a given relation, the spec is ambiguous. You could render that as either a single object or as a single-item array. By default, Spring HATEOAS uses the most terse approach and renders a single-link relation like this: Example 25. HAL document with single link rendered as an object ``` { "_links": { "item": { "href": "https://myhost/inventory/12" } }, "customer": "Dave Matthews" } ``` Some users prefer to not switch between arrays and objects when consuming HAL. They would prefer this type of rendering: Example 26. HAL with single link rendered as an array ``` { "_links": { "item": [{ "href": "https://myhost/inventory/12" }] }, "customer": "Dave Matthews" } ``` If you wish to customize this policy, all you have to do is inject a `HalConfiguration` bean into your application configuration. There are multiple choices. Example 27. Global HAL single-link rendering policy ``` @Bean public HalConfiguration globalPolicy() { return new HalConfiguration() // .withRenderSingleLinks(RenderSingleLinks.AS_ARRAY); (1) } ``` |**1**|Override Spring HATEOAS’s default by rendering ALL single-link relations as arrays.| |-----|-----------------------------------------------------------------------------------| If you prefer to only override some particular link relations, you can create a `HalConfiguration`bean like this: Example 28. Link relation-based HAL single-link rendering policy ``` @Bean public HalConfiguration linkRelationBasedPolicy() { return new HalConfiguration() // .withRenderSingleLinksFor( // IanaLinkRelations.ITEM, RenderSingleLinks.AS_ARRAY) (1) .withRenderSingleLinksFor( // LinkRelation.of("prev"), RenderSingleLinks.AS_SINGLE); (2) } ``` |**1**| Always render `item` link relations as an array. | |-----|----------------------------------------------------------------------| |**2**|Render `prev` link relations as an object when there is only one link.| If neither of these match your needs, you can use an Ant-style path pattern: Example 29. Pattern-based HAL single-link rendering policy ``` @Bean public HalConfiguration patternBasedPolicy() { return new HalConfiguration() // .withRenderSingleLinksFor( // "http*", RenderSingleLinks.AS_ARRAY); (1) } ``` |**1**|Render all link relations that start with `http` as an array.| |-----|-------------------------------------------------------------| | |The pattern-based approach uses Spring’s `AntPathMatcher`.| |---|----------------------------------------------------------| All of these `HalConfiguration` withers can be combined to form one comprehensive policy. Be sure to test your API extensively to avoid surprises. #### 4.1.3. Link title internationalization HAL defines a `title` attribute for its link objects. These titles can be populated by using Spring’s resource bundle abstraction and a resource bundle named `rest-messages` so that clients can use them in their UIs directly. This bundle will be set up automatically and is used during HAL link serialization. To define a title for a link, use the key template `_links.$relationName.title` as follows: Example 30. A sample `rest-messages.properties` ``` _links.cancel.title=Cancel order _links.payment.title=Proceed to checkout ``` This will result in the following HAL representation: Example 31. A sample HAL document with link titles defined ``` { "_links" : { "cancel" : { "href" : "…" "title" : "Cancel order" }, "payment" : { "href" : "…" "title" : "Proceed to checkout" } } } ``` #### Using the `CurieProvider` API The [Web Linking RFC](https://tools.ietf.org/html/rfc8288#section-2.1) describes registered and extension link relation types. Registered rels are well-known strings registered with the [IANA registry of link relation types](https://www.iana.org/assignments/link-relations/link-relations.xhtml). Extension `rel` URIs can be used by applications that do not wish to register a relation type. Each one is a URI that uniquely identifies the relation type. The `rel` URI can be serialized as a compact URI or [Curie](https://www.w3.org/TR/curie). For example, a curie of `ex:persons` stands for the link relation type `[example.com/rels/persons](https://example.com/rels/persons)` if `ex` is defined as `[example.com/rels/{rel}](https://example.com/rels/{rel})`. If curies are used, the base URI must be present in the response scope. The `rel` values created by the default `RelProvider` are extension relation types and, as a result, must be URIs, which can cause a lot of overhead. The `CurieProvider` API takes care of that: It lets you define a base URI as a URI template and a prefix that stands for that base URI. If a `CurieProvider` is present, the `RelProvider` prepends all `rel` values with the curie prefix. Furthermore a `curies` link is automatically added to the HAL resource. The following configuration defines a default curie provider: ``` @Configuration @EnableWebMvc @EnableHypermediaSupport(type= {HypermediaType.HAL}) public class Config { @Bean public CurieProvider curieProvider() { return new DefaultCurieProvider("ex", new UriTemplate("https://www.example.com/rels/{rel}")); } } ``` Note that now the `ex:` prefix automatically appears before all rel values that are not registered with IANA, as in `ex:orders`. Clients can use the `curies` link to resolve a curie to its full form. The following example shows how to do so: ``` { "_links": { "self": { "href": "https://myhost/person/1" }, "curies": { "name": "ex", "href": "https://example.com/rels/{rel}", "templated": true }, "ex:orders": { "href": "https://myhost/person/1/orders" } }, "firstname": "Dave", "lastname": "Matthews" } ``` Since the purpose of the `CurieProvider` API is to allow for automatic curie creation, you can define only one `CurieProvider` bean per application scope. ### 4.2. HAL-FORMS [HAL-FORMS](https://rwcbook.github.io/hal-forms/) is designed to add runtime FORM support to the [HAL media type](#mediatypes.hal). > > > > > HAL-FORMS "looks like HAL." However, it is important to keep in mind that HAL-FORMS is not the same as HAL — the two > should not be thought of as interchangeable in any way. > > > > — Mike Amundsen > HAL-FORMS spec To enable this media type, put the following configuration in your code: Example 32. HAL-FORMS enabled application ``` @Configuration @EnableHypermediaSupport(type = HypermediaType.HAL_FORMS) public class HalFormsApplication { } ``` Anytime a client supplies an `Accept` header with `application/prs.hal-forms+json`, you can expect something like this: Example 33. HAL-FORMS sample document ``` { "firstName" : "Frodo", "lastName" : "Baggins", "role" : "ring bearer", "_links" : { "self" : { "href" : "http://localhost:8080/employees/1" } }, "_templates" : { "default" : { "method" : "put", "contentType" : "", "properties" : [ { "name" : "firstName", "required" : true }, { "name" : "lastName", "required" : true }, { "name" : "role", "required" : true } ] }, "partiallyUpdateEmployee" : { "method" : "patch", "contentType" : "", "properties" : [ { "name" : "firstName", "required" : false }, { "name" : "lastName", "required" : false }, { "name" : "role", "required" : false } ] } } } ``` Check out the [HAL-FORMS spec](https://rwcbook.github.io/hal-forms/) to understand the details of the **\_templates** attribute. Read about the [Affordances API](#server.affordances) to augment your controllers with this extra metadata. As for single-item (`EntityModel`) and aggregate root collections (`CollectionModel`), Spring HATEOAS renders them identically to [HAL documents](#mediatypes.hal). #### 4.2.1. Defining HAL-FORMS metadata HAL-FORMS allows to describe criterias for each form field. Spring HATEOAS allows to customize those by shaping the model type for the input and output types and using annotations on them. |Attribute | Description | |----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |`readOnly`|Set to `true` if there’s no setter method for the property. If that is present, use Jackson’s `@JsonProperty(Access.READ_ONLY)` on the accessors or field explicitly. Not rendered by default, thus defaulting to `false`.| | `regex` | Can be customized by using JSR-303’s `@Pattern` annotation either on the field or a type. In case of the latter the pattern will be used for every property declared as that particular type. Not rendered by default. | |`required`| Can be customized by using JSR-303’s `@NotNull`. Not rendered by default and thus defaulting to `false`. Templates using `PATCH` as method will automatically have all properties set to not required. | For types that you cannot annotate manually, you can register a custom pattern via a `HalFormsConfiguration` bean present in the application context. ``` @Configuration class CustomConfiguration { @Bean HalFormsConfiguration halFormsConfiguration() { HalFormsConfiguration configuration = new HalFormsConfiguration(); configuration.registerPatternFor(CreditCardNumber.class, "[0-9]{16}"); } } ``` This setup will cause the HAL-FORMS template properties for representation model properties of type `CreditCardNumber` to declare a `regex` field with value `[0-9]{16}`. #### 4.2.2. Internationalization of form attributes HAL-FORMS contains attributes that are intended for human interpretation, like a template’s title or property prompts. These can be defined and internationalized using Spring’s resource bundle support and the `rest-messages` resource bundle configured by Spring HATEOAS by default. ##### Template titles To define a template title use the following pattern: `_templates.$affordanceName.title`. Note that in HAL-FORMS, the name of a template is `default` if it is the only one. This means that you’ll usually have to qualify the key with the local or fully qualified input type name that affordance describes. Example 34. Defining HAL-FORMS template titles ``` _templates.default.title=Some title (1) _templates.putEmployee.title=Create employee (2) Employee._templates.default.title=Create employee (3) com.acme.Employee._templates.default.title=Create employee (4) ``` |**1**| A global definition for the title using `default` as key. | |-----|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |**2**|A global definition for the title using the actual affordance name as key. Unless defined explicitly when creating the affordance, this defaults to `$httpMethod + $simpleInputTypeName`.| |**3**| A locally defined title to be applied to all types named `Employee`. | |**4**| A title definition using the fully-qualified type name. | | |Keys using the actual affordance name enjoy preference over the defaulted ones.| |---|-------------------------------------------------------------------------------| ##### Property prompts Property prompts can also be resolved via the `rest-messages` resource bundle automatically configured by Spring HATEOAS. The keys can be defined globally, locally or fully-qualified and need an `._prompt` concatenated to the actual property key: Example 35. Defining prompts for an `email` property ``` firstName._prompt=Firstname (1) Employee.firstName._prompt=Firstname (2) com.acme.Employee.firstName._prompt=Firstname (3) ``` |**1**|All properties named `firstName` will get "Firstname" rendered, independent of the type they’re declared in.| |-----|------------------------------------------------------------------------------------------------------------| |**2**| The `firstName` property in types named `Employee` will be prompted "Firstname". | |**3**| The `firstName` property of `com.acme.Employee` will get a prompt of "Firstname" assigned. | A sample document with both template titles and property prompts defined would then look something like this: Example 36. A sample HAL-FORMS document with internationalized template titles and property prompts ``` { …, "_templates" : { "default" : { "title" : "Create employee", "method" : "put", "contentType" : "", "properties" : [ { "name" : "firstName", "prompt" : "Firstname", "required" : true }, { "name" : "lastName", "prompt" : "Lastname", "required" : true }, { "name" : "role", "prompt" : "Role", "required" : true } ] } } } ``` ### 4.3. HTTP Problem Details [Problem Details for HTTP APIs](https://tools.ietf.org/html/rfc7807) is a media type to carry machine-readable details of errors in a HTTP response to avoid the need to define new error response formats for HTTP APIs. HTTP Problem Details defines a set of JSON properties that carry additional information to describe error details to HTTP clients. Find more details about those properties in particular in the relevant section of the [RFC document](https://tools.ietf.org/html/rfc7807#section-3.1). You can create such a JSON response by using the `Problem` media type domain type in your Spring MVC Controller: Reporting problem details using Spring HATEOAS' `Problem` type ``` @RestController class PaymentController { @PutMapping ResponseEntity issuePayment(@RequestBody PaymentRequest request) { PaymentResult result = payments.issuePayment(request.orderId, request.amount); if (result.isSuccess()) { return ResponseEntity.ok(result); } String title = messages.getMessage("payment.out-of-credit"); String detail = messages.getMessage("payment.out-of-credit.details", // new Object[] { result.getBalance(), result.getCost() }); Problem problem = Problem.create() (1) .withType(OUT_OF_CREDIT_URI) // .withTitle(title) (2) .withDetail(detail) // .withInstance(PAYMENT_ERROR_INSTANCE.expand(result.getPaymentId())) // .withProperties(map -> { (3) map.put("balance", result.getBalance()); map.put("accounts", Arrays.asList( // ACCOUNTS.expand(result.getSourceAccountId()), // ACCOUNTS.expand(result.getTargetAccountId()) // )); }); return ResponseEntity.status(HttpStatus.FORBIDDEN) // .body(problem); } } ``` |**1**| You start by creating an instance of `Problem` using the factory methods exposed. | |-----|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |**2**|You can define the values for the default properties defined by the media type, e.g. the type URI, the title and details using internationalization features of Spring (see above).| |**3**| Custom properties can be added via a `Map` or an explicit object (see below). | To use a dedicated object for custom properties, declare a type, create and populate an instance of it and hand this into the `Problem` instance either via `….withProperties(…)` or on instance creation via `Problem.create(…)`. Using a dedicated type to capture extended problem properties ``` class AccountDetails { int balance; List accounts; } problem.withProperties(result.getDetails()); // or Problem.create(result.getDetails()); ``` This will result in a response looking like this: A sample HTTP Problem Details response ``` { "type": "https://example.com/probs/out-of-credit", "title": "You do not have enough credit.", "detail": "Your current balance is 30, but that costs 50.", "instance": "/account/12345/msgs/abc", "balance": 30, "accounts": ["/account/12345", "/account/67890"] } ``` ### 4.4. Collection+JSON [Collection+JSON](http://amundsen.com/media-types/collection/format/) is a JSON spec registered with IANA-approved media type `application/vnd.collection+json`. > > > > > [Collection+JSON](http://amundsen.com/media-types/collection/) is a JSON-based read/write hypermedia-type designed to support > management and querying of simple collections. > > > > — Mike Amundsen > Collection+JSON spec Collection+JSON provides a uniform way to represent both single item resources as well as collections. To enable this media type, put the following configuration in your code: Example 37. Collection+JSON enabled application ``` @Configuration @EnableHypermediaSupport(type = HypermediaType.COLLECTION_JSON) public class CollectionJsonApplication { } ``` This configuration will make your application respond to requests that have an `Accept` header of `application/vnd.collection+json`as shown below. The following example from the spec shows a single item: Example 38. Collection+JSON single item example ``` { "collection": { "version": "1.0", "href": "https://example.org/friends/", (1) "links": [ (2) { "rel": "feed", "href": "https://example.org/friends/rss" }, { "rel": "queries", "href": "https://example.org/friends/?queries" }, { "rel": "template", "href": "https://example.org/friends/?template" } ], "items": [ (3) { "href": "https://example.org/friends/jdoe", "data": [ (4) { "name": "fullname", "value": "J. Doe", "prompt": "Full Name" }, { "name": "email", "value": "[email protected]", "prompt": "Email" } ], "links": [ (5) { "rel": "blog", "href": "https://examples.org/blogs/jdoe", "prompt": "Blog" }, { "rel": "avatar", "href": "https://examples.org/images/jdoe", "prompt": "Avatar", "render": "image" } ] } ] } } ``` |**1**| The `self` link is stored in the document’s `href` attribute. | |-----|---------------------------------------------------------------------------------------------------------------| |**2**| The document’s top `links` section contains collection-level links (minus the `self` link). | |**3**|The `items` section contains a collection of data. Since this is a single-item document, it only has one entry.| |**4**| The `data` section contains actual content. It’s made up of properties. | |**5**| The item’s individual `links`. | | |The previous fragment was lifted from the spec. When Spring HATEOAS renders an `EntityModel`, it will:

* Put the `self` link into both the document’s `href` attribute and the item-level `href` attribute.

* Put the rest of the model’s links into both the top-level `links` as well as the item-level `links`.

* Extract the properties from the `EntityModel` and turn them into …​| |---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| When rendering a collection of resources, the document is almost the same, except there will be multiple entries inside the `items` JSON array, one for each entry. Spring HATEOAS more specifically will: * Put the entire collection’s `self` link into the top-level `href` attribute. * The `CollectionModel` links (minus `self`) will be put into the top-level `links`. * Each item-level `href` will contain the corresponding `self` link for each entry from the `CollectionModel.content` collection. * Each item-level `links` will contain all other links for each entry from `CollectionModel.content`. ### 4.5. UBER - Uniform Basis for Exchanging Representations [UBER](https://rawgit.com/uber-hypermedia/specification/master/uber-hypermedia.html) is an experimental JSON spec > > > > > The UBER document format is a minimal read/write hypermedia type designed to support simple state transfers and ad-hoc > hypermedia-based transitions. > > > > — Mike Amundsen > UBER spec UBER provides a uniform way to represent both single item resources as well as collections. To enable this media type, put the following configuration in your code: Example 39. UBER+JSON enabled application ``` @Configuration @EnableHypermediaSupport(type = HypermediaType.UBER) public class UberApplication { } ``` This configuration will make your application respond to requests using the `Accept` header `application/vnd.amundsen-uber+json`as show below: Example 40. UBER sample document ``` { "uber" : { "version" : "1.0", "data" : [ { "rel" : [ "self" ], "url" : "/employees/1" }, { "name" : "employee", "data" : [ { "name" : "role", "value" : "ring bearer" }, { "name" : "name", "value" : "Frodo" } ] } ] } } ``` This media type is still under development as is the spec itself. Feel free to[open a ticket](https://github.com/spring-projects/spring-hateoas/issues) if you run into issues using it. | |**UBER media type** is not associated in any way with **Uber Technologies Inc.**, the ride sharing company.| |---|-----------------------------------------------------------------------------------------------------------| ### 4.6. ALPS - Application-Level Profile Semantics [ALPS](https://tools.ietf.org/html/draft-amundsen-richardson-foster-alps-01) is a media type for providing profile-based metadata about another resource. > > > > > An ALPS document can be used as a profile to > explain the application semantics of a document with an application- > agnostic media type (such as HTML, HAL, Collection+JSON, Siren, > etc.). This increases the reusability of profile documents across > media types. > > > > — Mike Amundsen > ALPS spec ALPS requires no special activation. Instead you "build" an `Alps` record and return it from either a Spring MVC or a Spring WebFlux web method as shown below: Example 41. Building an `Alps` record ``` @GetMapping(value = "/profile", produces = ALPS_JSON_VALUE) Alps profile() { return Alps.alps() // .doc(doc() // .href("https://example.org/samples/full/doc.html") // .value("value goes here") // .format(Format.TEXT) // .build()) // .descriptor(getExposedProperties(Employee.class).stream() // .map(property -> Descriptor.builder() // .id("class field [" + property.getName() + "]") // .name(property.getName()) // .type(Type.SEMANTIC) // .ext(Ext.builder() // .id("ext [" + property.getName() + "]") // .href("https://example.org/samples/ext/" + property.getName()) // .value("value goes here") // .build()) // .rt("rt for [" + property.getName() + "]") // .descriptor(Collections.singletonList(Descriptor.builder().id("embedded").build())) // .build()) // .collect(Collectors.toList())) .build(); } ``` * This example leverages `PropertyUtils.getExposedProperties()` to extract metadata about the domain object’s attributes. This fragment has test data plugged in. It yields JSON like this: Example 42. ALPS JSON ``` { "version": "1.0", "doc": { "format": "TEXT", "href": "https://example.org/samples/full/doc.html", "value": "value goes here" }, "descriptor": [ { "id": "class field [name]", "name": "name", "type": "SEMANTIC", "descriptor": [ { "id": "embedded" } ], "ext": { "id": "ext [name]", "href": "https://example.org/samples/ext/name", "value": "value goes here" }, "rt": "rt for [name]" }, { "id": "class field [role]", "name": "role", "type": "SEMANTIC", "descriptor": [ { "id": "embedded" } ], "ext": { "id": "ext [role]", "href": "https://example.org/samples/ext/role", "value": "value goes here" }, "rt": "rt for [role]" } ] } ``` Instead of linking each field "automatically" to a domain object’s fields, you can write them by hand if you like. It’s also possible to use Spring Framework’s message bundles and the `MessageSource` interface. This gives you the ability to delegate these values to locale-specific message bundles and even internationalize the metadata. ### 4.7. Community-based media types Thanks to the [ability to create your own media type](#mediatypes.custom), there are several community-led efforts to build additional media types. #### 4.7.1. JSON:API * [Specification](https://jsonapi.org) * Media type designation: `application/vnd.api+json` * Latest Release * [Reference documentation](https://toedter.github.io/spring-hateoas-jsonapi/release/reference/index.html) * [API documentation](https://toedter.github.io/spring-hateoas-jsonapi/release/api/index.html) * Current Snapshot * [Reference documentation](https://toedter.github.io/spring-hateoas-jsonapi/snapshot/reference/index.html) * [API documentation](https://toedter.github.io/spring-hateoas-jsonapi/snapshot/api/index.html) * [Source](https://github.com/toedter/spring-hateoas-jsonapi) * Project Lead: [Kai Toedter](https://github.com/toedter) Maven coordinates ``` com.toedter spring-hateoas-jsonapi {see project page for current version} ``` Gradle coordinates ``` implementation 'com.toedter:spring-hateoas-jsonapi:{see project page for current version}' ``` Visit the project page for more details if you want snapshot releases. #### 4.7.2. Siren * [Specification](https://github.com/kevinswiber/siren) * Media type designation: `application/vnd.siren+json` * [Reference documentation](https://spring-hateoas-siren.ingogriebsch.de) * [javadocs](https://spring-hateoas-siren.ingogriebsch.de/apidocs) * [Source](https://github.com/ingogriebsch/spring-hateoas-siren) * Project Lead: [Ingo Griebsch](https://github.com/ingogriebsch) Maven coordinates ``` de.ingogriebsch.hateoas spring-hateoas-siren {see project page for current version} compile ``` Gradle coordinates ``` implementation 'de.ingogriebsch.hateoas:spring-hateoas-siren:{see project page for current version}' ``` ### 4.8. Registering a custom media type Spring HATEOAS allows you to integrate custom media types through an SPI. The building blocks of such an implementation are: 1. Some form of Jackson `ObjectMapper` customization. In its most simple case that’s a Jackson `Module` implementation. 2. A `LinkDiscoverer` implementation so that the client-side support is able to detect links in representations. 3. A small bit of infrastructure configuration that will allow Spring HATEOAS to find the custom implementation and pick it up. #### 4.8.1. Custom media type configuration Custom media type implementations are picked up by Spring HATEOAS by scanning the application context for any implementations of the `HypermediaMappingInformation` interface. Each media type must implement this interface in order to: * Be applied to [`WebClient`](#client.web-client), [`WebTestClient`](#client.web-test-client), or [`RestTemplate`](#client.rest-template) instances. * Support serving that media type from Spring Web MVC and Spring WebFlux controllers. To define your own media type could look as simple as this: ``` @Configuration public class MyMediaTypeConfiguration implements HypermediaMappingInformation { @Override public List getMediaTypes() { return MediaType.parse("application/vnd-acme-media-type") (1) } @Override public Module getJacksonModule() { return new Jackson2MyMediaTypeModule(); (2) } @Bean MyLinkDiscoverer myLinkDiscoverer() { return new MyLinkDiscoverer(); (3) } } ``` |**1**|The configuration class returns the media type it supports. This applies to both server-side and client-side scenarios.| |-----|-----------------------------------------------------------------------------------------------------------------------| |**2**| It overrides `getJacksonModule()` to provide custom serializers to create the media type specific representations. | |**3**| It also declares a custom `LinkDiscoverer` implementation for further client-side support. | The Jackson module usually declares `Serializer` and `Deserializer` implementations for the representation model types `RepresentationModel`, `EntityModel`, `CollectionModel` and `PagedModel`. In case you need further customization of the Jackson `ObjectMapper` (like a custom `HandlerInstantiator`), you can alternatively override `configureObjectMapper(…)`. | |Prior versions of reference documentation has mentioned implementing the `MediaTypeConfigurationProvider` interface and registering it with `spring.factories`.
This is NOT necessary.
This SPI is ONLY used for out-of-the-box media types provided by Spring HATEOAS.
Merely implementing the `HypermediaMappingInformation` interface and registering it as a Spring bean is all that’s needed.| |---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| #### 4.8.2. Recommendations The preferred way to implement media type representations is by providing a type hierarchy that matches the expected format and can be serialized by Jackson as is. In the `Serializer` and `Deserializer` implementations registered for `RepresentationModel`, convert the instances into the media type-specific model types and then lookup the Jackson serializer for those. The media types supported by default use the same configuration mechanism as third-party implementations would do. So it’s worth studying the implementations in [the `mediatype` package](https://github.com/spring-projects/spring-hateoas/tree/master/src/main/java/org/springframework/hateoas/mediatype). Note, that the built in media type implementations keep their configuration classes package private, as they’re activated via `@EnableHypermediaSupport`. Custom implementations should probably make those public instead to make sure, users can import those configuration classes from their application packages. ## 5. Configuration This section describes how to configure Spring HATEOAS. ### 5.1. Using `@EnableHypermediaSupport` To let the `RepresentationModel` subtypes be rendered according to the specification of various hypermedia representation types, you can activate support for a particular hypermedia representation format through `@EnableHypermediaSupport`. The annotation takes a `HypermediaType` enumeration as its argument. Currently, we support [HAL](https://tools.ietf.org/html/draft-kelly-json-hal) as well as a default rendering. Using the annotation triggers the following: * It registers necessary Jackson modules to render `EntityModel` and `CollectionModel` in the hypermedia specific format. * If JSONPath is on the classpath, it automatically registers a `LinkDiscoverer` instance to look up links by their `rel` in plain JSON representations (see [Using `LinkDiscoverer` Instances](#client.link-discoverer)). * By default, it enables [entity links](#fundamentals.obtaining-links.entity-links) and automatically picks up `EntityLinks` implementations and bundles them into a `DelegatingEntityLinks` instance that you can autowire. * It automatically picks up all `RelProvider` implementations in the `ApplicationContext` and bundles them into a `DelegatingRelProvider` that you can autowire. It registers providers to consider `@Relation` on domain types as well as Spring MVC controllers. If the [EVO inflector](https://github.com/atteo/evo-inflector) is on the classpath, collection `rel` values are derived by using the pluralizing algorithm implemented in the library (see [[spis.rel-provider]](#spis.rel-provider)). #### 5.1.1. Explicitly enabling support for dedicated web stacks By default, `@EnableHypermediaSupport` will reflectively detect the web application stack you’re using and hook into the Spring components registered for those to enable support for hypermedia representations. However, there are situations in which you’d only explicitly want to activate support for a particular stack. E.g. if your Spring WebMVC based application uses WebFlux' `WebClient` to make outgoing requests and that one is not supposed to work with hypermedia elements, you can restrict the functionality to be enabled by explicitly declaring WebMVC in the configuration: Example 43. Explicitly activating hypermedia support for a particular web stack ``` @EnableHypermediaSupport(…, stacks = WebStack.WEBMVC) class MyHypermediaConfiguration { … } ``` ## 6. Client-side Support This section describes Spring HATEOAS’s support for clients. ### 6.1. Traverson Spring HATEOAS provides an API for client-side service traversal. It is inspired by the [Traverson JavaScript library](https://blog.codecentric.de/en/2013/11/traverson/). The following example shows how to use it: ``` Map parameters = new HashMap<>(); parameters.put("user", 27); Traverson traverson = new Traverson(URI.create("http://localhost:8080/api/"), MediaTypes.HAL_JSON); String name = traverson .follow("movies", "movie", "actor").withTemplateParameters(parameters) .toObject("$.name"); ``` You can set up a `Traverson` instance by pointing it to a REST server and configuring the media types you want to set as `Accept` headers. You can then define the relation names you want to discover and follow. Relation names can either be simple names or JSONPath expressions (starting with an `$`). The sample then hands a parameter map into the `Traverson` instance. The parameters are used to expand URIs (which are templated) found during the traversal. The traversal is concluded by accessing the representation of the final traversal. In the preceding example, we evaluate a JSONPath expression to access the actor’s name. The preceding example is the simplest version of traversal, where the `rel` values are strings and, at each hop, the same template parameters are applied. There are more options to customize template parameters at each level. The following example shows these options. ``` ParameterizedTypeReference> resourceParameterizedTypeReference = new ParameterizedTypeReference>() {}; EntityModel itemResource = traverson.// follow(rel("items").withParameter("projection", "noImages")).// follow("$._embedded.items[0]._links.self.href").// toObject(resourceParameterizedTypeReference); ``` The static `rel(…​)` function is a convenient way to define a single `Hop`. Using `.withParameter(key, value)` makes it simple to specify URI template variables. | |`.withParameter()` returns a new `Hop` object that is chainable. You can string together as many `.withParameter` as you like. The result is a single `Hop` definition.
The following example shows one way to do so:| |---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ``` ParameterizedTypeReference> resourceParameterizedTypeReference = new ParameterizedTypeReference>() {}; Map params = Collections.singletonMap("projection", "noImages"); EntityModel itemResource = traverson.// follow(rel("items").withParameters(params)).// follow("$._embedded.items[0]._links.self.href").// toObject(resourceParameterizedTypeReference); ``` You can also load an entire `Map` of parameters by using `.withParameters(Map)`. | |`follow()` is chainable, meaning you can string together multiple hops, as shown in the preceding examples. You can either put multiple string-based `rel` values (`follow("items", "item")`) or a single hop with specific parameters.| |---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| #### 6.1.1. `EntityModel` vs. `CollectionModel` The examples shown so far demonstrate how to sidestep Java’s type erasure and convert a single JSON-formatted resource into a `EntityModel` object. However, what if you get a collection like an `\_embedded` HAL collection? You can do so with only one slight tweak, as the following example shows: ``` CollectionModelType collectionModelType = TypeReferences.CollectionModelType() {}; CollectionModel itemResource = traverson.// follow(rel("items")).// toObject(collectionModelType); ``` Instead of fetching a single resource, this one deserializes a collection into `CollectionModel`. ### 6.2. Using `LinkDiscoverer` Instances When working with hypermedia enabled representations, a common task is to find a link with a particular relation type in it. Spring HATEOAS provides [JSONPath](https://code.google.com/p/json-path)-based implementations of the `LinkDiscoverer` interface for either the default representation rendering or HAL out of the box. When using `@EnableHypermediaSupport`, we automatically expose an instance supporting the configured hypermedia type as a Spring bean. Alternatively, you can set up and use an instance as follows: ``` String content = "{'_links' : { 'foo' : { 'href' : '/foo/bar' }}}"; LinkDiscoverer discoverer = new HalLinkDiscoverer(); Link link = discoverer.findLinkWithRel("foo", content); assertThat(link.getRel(), is("foo")); assertThat(link.getHref(), is("/foo/bar")); ``` ### 6.3. Configuring WebClient instances If you need configure a `WebClient` to speak hypermedia, it’s easy. Get a hold of the `HypermediaWebClientConfigurer` as shown below: Example 44. Configuring a `WebClient` yourself ``` @Bean WebClient.Builder hypermediaWebClient(HypermediaWebClientConfigurer configurer) { (1) return configurer.registerHypermediaTypes(WebClient.builder()); (2) } ``` |**1**|Inside your `@Configuration` class, get a copy of the `HypermediaWebClientConfigurer` bean Spring HATEOAS registers.| |-----|--------------------------------------------------------------------------------------------------------------------| |**2**| After creating a `WebClient.Builder`, use the configurer to register hypermedia types. | | |What `HypermediaWebClientConfigurer` does it register all the right encoders and decoders with a `WebClient.Builder`. To make use of it,
you need to inject the builder somewhere into your application, and run the `build()` method to produce a `WebClient`.| |---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| If you’re using Spring Boot, there is another way: the `WebClientCustomizer`. Example 45. Letting Spring Boot configure things ``` @Bean (4) WebClientCustomizer hypermediaWebClientCustomizer(HypermediaWebClientConfigurer configurer) { (1) return webClientBuilder -> { (2) configurer.registerHypermediaTypes(webClientBuilder); (3) }; } ``` |**1**| When creating a Spring bean, request a copy of Spring HATEOAS’s `HypermediaWebClientConfigurer` bean. | |-----|----------------------------------------------------------------------------------------------------------------------------------| |**2**| Use a Java 8 lambda expression to define a `WebClientCustomizer`. | |**3**| Inside the function call, apply the `registerHypermediaTypes` method. | |**4**|Return the whole thing as a Spring bean so Spring Boot can pick it up and apply it to its autoconfigured `WebClient.Builder` bean.| At this stage, whenever you need a concrete `WebClient`, simply inject `WebClient.Builder` into your code, and use `build()`. The `WebClient` instance will be able to interact using hypermedia. ### 6.4. Configuring `WebTestClient` Instances When working with hypermedia-enabled representations, a common task is to run various tests by using `WebTestClient`. To configure an instance of `WebTestClient` in a test case, check out this example: Example 46. Configuring `WebTestClient` when using Spring HATEOAS ``` @Test // #1225 void webTestClientShouldSupportHypermediaDeserialization() { // Configure an application context programmatically. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(HalConfig.class); (1) context.refresh(); // Create an instance of a controller for testing WebFluxEmployeeController controller = context.getBean(WebFluxEmployeeController.class); controller.reset(); // Extract the WebTestClientConfigurer from the app context. HypermediaWebTestClientConfigurer configurer = context.getBean(HypermediaWebTestClientConfigurer.class); // Create a WebTestClient by binding to the controller and applying the hypermedia configurer. WebTestClient client = WebTestClient.bindToApplicationContext(context).build().mutateWith(configurer); (2) // Exercise the controller. client.get().uri("http://localhost/employees").accept(HAL_JSON) // .exchange() // .expectStatus().isOk() // .expectBody(new TypeReferences.CollectionModelType>() {}) (3) .consumeWith(result -> { CollectionModel> model = result.getResponseBody(); (4) // Assert against the hypermedia model. assertThat(model.getRequiredLink(IanaLinkRelations.SELF)).isEqualTo(Link.of("http://localhost/employees")); assertThat(model.getContent()).hasSize(2); }); } ``` |**1**| Register your configuration class that uses `@EnableHypermediaSupport` to enable HAL support. | |-----|----------------------------------------------------------------------------------------------------------------------------------| |**2**| Use `HypermediaWebTestClientConfigurer` to apply hypermedia support. | |**3**|Ask for a response of `CollectionModel>` using Spring HATEOAS’s `TypeReferences.CollectionModelType` helper.| |**4**| After getting the "body" in Spring HATEOAS format, assert against it! | | |`WebTestClient` is an immutable value type, so you can’t alter it in place. `HypermediaWebClientConfigurer` returns a mutated
variant that you must then capture to use it.| |---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| If you are using Spring Boot, there are additional options, like this: Example 47. Configuring `WebTestClient` when using Spring Boot ``` @SpringBootTest @AutoConfigureWebTestClient (1) class WebClientBasedTests { @Test void exampleTest(@Autowired WebTestClient.Builder builder, @Autowired HypermediaWebTestClientConfigurer configurer) { (2) client = builder.apply(configurer).build(); (3) client.get().uri("/") // .exchange() // .expectBody(new TypeReferences.EntityModelType() {}) (4) .consumeWith(result -> { // assert against this EntityModel! }); } } ``` |**1**| This is Spring Boot’s test annotation that will configure a `WebTestClient.Builder` for this test class. | |-----|-------------------------------------------------------------------------------------------------------------------| |**2**|Autowire Spring Boot’s `WebTestClient.Builder` into `builder` and Spring HATEOAS’s configurer as method parameters.| |**3**| Use `HypermediaWebTestClientConfigurer` to register support for hypermedia. | |**4**| Signal you want an `EntityModel` returned using `TypeReferences`. | Again, you can use similar assertions as the earlier example. There are many other ways to fashion test cases. `WebTestClient` can be bound to controllers, functions, and URLs. This section isn’t meant to show all that. Instead, this gives you some examples to get started. The important thing is that by applying `HypermediaWebTestClientConfigurer`, any instance of `WebTestClient` can be altered to handle hypermedia. ### 6.5. Configuring RestTemplate instances If you want to create your own copy of `RestTemplate`, configured to speak hypermedia, you can use the `HypermediaRestTemplateConfigurer`: Example 48. Configuring `RestTemplate` yourself ``` /** * Use the {@link HypermediaRestTemplateConfigurer} to configure a {@link RestTemplate}. */ @Bean RestTemplate hypermediaRestTemplate(HypermediaRestTemplateConfigurer configurer) { (1) return configurer.registerHypermediaTypes(new RestTemplate()); (2) } ``` |**1**|Inside your `@Configuration` class, get a copy of the `HypermediaRestTemplateConfigurer` bean Spring HATEOAS registers.| |-----|-----------------------------------------------------------------------------------------------------------------------| |**2**| After creating a `RestTemplate`, use the configurer to apply hypermedia types. | You are free to apply this pattern to any instance of `RestTemplate` that you need, whether is to create a registered bean, or inside a service you define. If you’re using Spring Boot, there is another approach. In general, Spring Boot has moved away from the concept of registering a `RestTemplate` bean in the application context. * When talking to different services, you often need different credentials. * When `RestTemplate` uses an underlying connection pool, you run into additional issues. * Users often need different instances rather than a single bean. To compensate for this, Spring Boot provides a `RestTemplateBuilder`. This autoconfigured bean lets you define various beans used to fashion a `RestTemplate` instance. You ask for a `RestTemplateBuilder` bean, call its `build()` method, and then apply final settings (such as credentials and other details). To register hypermedia-based message converters, add the following to your code: Example 49. Letting Spring Boot configure things ``` @Bean (4) RestTemplateCustomizer hypermediaRestTemplateCustomizer(HypermediaRestTemplateConfigurer configurer) { (1) return restTemplate -> { (2) configurer.registerHypermediaTypes(restTemplate); (3) }; } ``` |**1**| When creating a Spring bean, request a copy of Spring HATEOAS’s `HypermediaRestTemplateConfigurer` bean. | |-----|-------------------------------------------------------------------------------------------------------------------------------| |**2**| Use a Java 8 lambda expression to define a `RestTemplateCustomizer`. | |**3**| Inside the function call, apply the `registerHypermediaTypes` method. | |**4**|Return the whole thing as a Spring bean so Spring Boot can pick it up and apply it to its autoconfigured `RestTemplateBuilder`.| At this stage, whenever you need a concrete `RestTemplate`, simply inject `RestTemplateBuilder` into your code, and use `build()`. The `RestTemplate` instance will be able to interact using hypermedia.