= Spring HATEOAS - Hypermedia Example

This guide shows a more detailed foray into linking resources with hypermedia. It includes automated links, custom ones,
and retaining legacy links to support older clients.

Before proceeding, have you read these yet?

. link:../basics[Spring HATEOAS - Basic Example]
. link:../api-evolution[Spring HATEOAS - API Evolution Example]

You may wish to read them first before reading this one.

NOTE: This example uses https://projectlombok.org[Project Lombok] to reduce writing Java code.

== Defining Your Domain

This example takes off where Basics and API Evolution end: an employee payroll system. Only this time, you'll introduce
a new domain: *managers*.

You'll explore how to create create REST representations for a manager and tie it into employees.

For starters, here is the basic definition:

[source,java]
----
@Data
@Entity
@NoArgsConstructor
class Manager {

	@Id @GeneratedValue
	private Long id;
	private String name;

	/**
	 * To break the recursive, bi-directional interface, don't serialize {@literal employees}.
	 */
	@JsonIgnore
	@OneToMany(mappedBy = "manager")
	private List<Employee> employees = new ArrayList<>();

	Manager(String name) {
		this.name = name;
	}
}
----

This is very similar to `Employee`:

* Uses the same `@Data` Lombok annotation to reduce boilerplate in defining a mutable value object.
* They are stored in a JPA data store using `@Entity`, `@Id`, and `@GeneratedValue`.
* Has a `@NoArgsConstructor` to support Jackson's serializers.

But it contains a new aspect: a 1-to-many relationship with `Employee` in the form a `List<Employee>`.

This domain object initializes the field with an empty list to avoid NPEs. The JPA `@OneToMany` annotation indicates
that the relationship between `Manager` and `Employee` is stored in the database tables in the `Employee` entity's
*manager* property, i.e. the manager's primary key will be stored as a foreign key in the *EMPLOYEE* table.

WARNING: Bi-directional relationships can be modeled in JPA, but you must carefully handle this. Jackson tends to
navigate as far as possible when serializing, so you have to tell it to stop with the `@JsonIgnore` directive. Otherwise,
it will generate a stack overflow exception when hopping Manager -> Employee -> Manager -> etc.

A handy constructor is also added to support link:src/main/java/org/springframework/hateoas/examples/DatabaseLoader.java[loading the database]
with sample data.

A corresponding Spring Data JPA repository is defined:

[source,java]
----
interface ManagerRepository extends CrudRepository<Manager, Long> {
}
----

To round things out, you need to make some updates to the `Employee` domain object:

[source,java]
----
@Data
@Entity
@NoArgsConstructor
class Employee {

	@Id @GeneratedValue
	private Long id;
	private String name;
	private String role;

	/**
	 * To break the recursive, bi-directional relationship, don't serialize {@literal manager}.
	 */
	@JsonIgnore
	@OneToOne
	private Manager manager;

	Employee(String name, String role, Manager manager) {

		this.name = name;
		this.role = role;
		this.manager = manager;
	}
}
----

This is very similar to what you saw in *Basics*, except that now there is a 1-to-1 JPA relationship in the *manager* field.

The constructor call has also been updated. Finally, the same stack overflow is blocked from this end by also putting a `@JsonIgnore`
Jackson annotation on the *manager* field.

With these changes in place, you can now define a `ResourceAssembler` for the `Manager`:

[source,java]
----
@Component
class ManagerResourceAssembler extends SimpleIdentifiableRepresentationModelAssembler<Manager> {

	ManagerResourceAssembler() {
		super(ManagerController.class);
	}
}
----

If you follow the same paradigm of extending Spring HATEOAS's `SimpleIdentifiableRepresentationModelAssembler` and applying the `Manager` type,
you can easily inherit links for */managers* and */managers/{id}*

Before we go any further, we need to define those links!

[source,java]
----
@RestController
class ManagerController {

	private final ManagerRepository repository;
	private final ManagerResourceAssembler assembler;

	ManagerController(ManagerRepository repository, ManagerResourceAssembler assembler) {

		this.repository = repository;
		this.assembler = assembler;
	}

	/**
	 * Look up all managers, and transform them into a REST collection resource using
	 * {@link ManagerResourceAssembler#toCollectionModel(Iterable)}. Then return them through
	 * Spring Web's {@link ResponseEntity} fluent API.
	 */
	@GetMapping("/managers")
	ResponseEntity<CollectionModel<EntityModel<Manager>>> findAll() {
		return ResponseEntity.ok(
			assembler.toCollectionModel(repository.findAll()));

	}

	/**
	 * Look up a single {@link Manager} and transform it into a REST resource using
	 * {@link ManagerResourceAssembler#toEntityModel(Object)}. Then return it through
	 * Spring Web's {@link ResponseEntity} fluent API.
	 *
	 * @param id
	 */
	@GetMapping("/managers/{id}")
	ResponseEntity<EntityModel<Manager>> findOne(@PathVariable long id) {
		return ResponseEntity.ok(
			assembler.toEntityModel(repository.findOne(id)));
	}
}
----

This controller should look familar, since it's almost identical to `EmployeeController` as seen in link:../api-evolution[API Evolution].
You have simply swapped */employees* with */managers* and plugged in `ManagerRepository` and `ManagerResourceAssembler`.

IMPORTANT: It's not a requirement to use a `ResourceAssembler`. But having one place to define all links for a given domain object
ensures a consistent representation.

With the basic routes defined, you could say we have an operational REST service. But it's not fleshed out very well. To truly
power up the hypermedia and serve clients, you need to add links _between_ the relevant domain types.

NOTE: Up until this point, we've been using the term "domain types" or "domain objects". This is lingo found in Domain Driven Design.
What you are building are *REST resources* and how the various media types they are represented in. The paradigm of REST is
to construct resources that contain both data for the client to consume as well as controls to navigate to related data.

The first link to navigate from a `Manager` resource to its related `Employee` resources would be a */managers/{id}/employees*
route. Since a controller that yields employee objects would be found in the `EmployeeController`, we need to make the following alterations:

.EmployeeController
[source,java]
----
@RestController
class EmployeeController {

	...
	
	/**
	 * Find an {@link Employee}'s {@link Manager} based upon employee id. Turn it into a context-based link.
	 *
	 * @param id
	 * @return
	 */
	@GetMapping("/managers/{id}/employees")
	public ResponseEntity<CollectionModel<EntityModel<Employee>>> findEmployees(@PathVariable long id) {
		return ResponseEntity.ok(
			assembler.toCollectionModel(repository.findByManagerId(id)));
	}
}
----

We've added another route, but how are we getting the data? Oh yeah, we need to add another finder!

[source,java]
----
interface EmployeeRepository extends CrudRepository<Employee, Long> {

	List<Employee> findByManagerId(Long id);

}
----

With Spring Data, we can define a new finder _just by writing it's method signature!_ This custom finder will navigate by property
and find a list of employees pointed at the chosen manager id.

NOTE: Navigation by property is analogous to writing `select EMPLOYEE.* from EMPLOYEE join MANAGER on MANAGER.PK = EMPLOYEE.FK where MANAGER.PK == :id`.
It makes it super simple to navigate over JPA relationships and find what we need.

This newly minted route needs to be added to every `Manager` representation we render. To do that, we need to make an alteration
to `ManagerResourceAssembler`:

[source,java]
----
@Component
class ManagerResourceAssembler extends SimpleIdentifiableRepresentationModelAssembler<Manager> {

	...

	/**
	 * Retain default links provided by {@link SimpleIdentifiableRepresentationModelAssembler}, but add extra ones to each {@link Manager}.
	 *
	 * @param resource
	 */
	@Override
	protected void addLinks(EntityModel<Manager> resource) {
		/**
		 * Retain default links.
		 */
		super.addLinks(resource);

		// Add custom link to find all managed employees
		resource.add(linkTo(methodOn(EmployeeController.class).findEmployees(resource.getContent().getId())).withRel("employees"));
	}

	...
}

----

`SimpleIdentifiableRepresentationModelAssembler` has methods to alter a resource representation for single items or collections. It has pre-baked
renderings to create a self link to a single item as well as a link back to the collection. In this code, you are extending that
method and invoking `super.addLinks()` in order to include those links. Then you add the link to the manager's employees you just created.

IMPORTANT: You can either _add_ to the links defined by `SimpleIdentifiableRepresentationModelAssembler` as shown, or you can totally replace them by _not_
invoking `super.addLinks()`. Your choice.

There is a corresponding combination of a route/repository finder/assembler to allow an employee to find his or her manager. It's left as an exericise
for you to discover it in `ManagerController`, `ManagerRepository`, and `EmployeeResourceAssembler`.

== Augmenting Representations

Some critics of REST will point to certain toolkits or coded solutions and argue that "hopping" can be inefficient. A common example is
a relational set of tables that through 3NF (3rd Normal Form) split up data between a parent/child relationship. In essence, part of the data
is in the parent table, part in the child table. The parent table's data is shown along with a link to navigate to the child table's data.

This is a false comparison, because REST wholely supports merging data if it makes sense. In DDD, such items are referred to as *aggregates*.
Nothing about a REST resource is confined by the rules of 3NF, written forty years ago. That can simply be shortfall of certain
toolkits (but not Spring HATEOAS!)

What if you wanted a detailed `Employee` representation that included the `Manager` details? No problem! Just model it.

[source,java]
----
@Value
@JsonPropertyOrder({"id", "name", "role", "manager"})
public class EmployeeWithManager {

	@JsonIgnore
	private final Employee employee;

	public Long getId() {
		return this.employee.getId();
	}

	public String getName() {
		return this.employee.getName();
	}

	public String getRole() {
		return this.employee.getRole();
	}

	public String getManager() {
		return this.employee.getManager().getName();
	}

}
----

This _immutable_ value object (thanks to Lombok's `@Value` annotation) is initialized with an `Employee` object. It defines
how it gets rendered through various getter methods. It also subtly does _not_ render the `Employee` object itself.

IMPORTANT: `Employee` and `Manager` both have a *name* field. With combined representations, there has to be agreement on how these
two fields will appear. In this case, `Employee.name` is kept and `Manager.name` is turned into *manager*.

To support this, we can write the corresponding route in `EmployeeController`:

[source,java]
----
@GetMapping("/employees/detailed")
public ResponseEntity<CollectionModel<EntityModel<EmployeeWithManager>>> findAllDetailedEmployees() {

	return ResponseEntity.ok(
		employeeWithManagerResourceAssembler.toCollectionModel(
			StreamSupport.stream(repository.findAll().spliterator(), false)
				.map(EmployeeWithManager::new)
				.collect(Collectors.toList())));
}

@GetMapping("/employees/{id}/detailed")
public ResponseEntity<EntityModel<EmployeeWithManager>> findDetailedEmployee(@PathVariable Long id) {

	Employee employee = repository.findOne(id);

	return ResponseEntity.ok(
		employeeWithManagerResourceAssembler.toEntityModel(
			new EmployeeWithManager(employee)));
}
----

This shows both a collection of "detailed" employees as well as a single one. The collection fetches all employees, uses a Java 8
stream to convert each `Employee` into an `EmployeeWithManager`, and wraps it into a Spring HATEOAS `Resources` collection.

The single employee version does the corresponding transformation against a single `Employee`.

To support building REST resources, you also need a `ResourceAssembler` for `EmployeeWithManager`. This should appear very
familiar by now:

[source,java]
----
@Component
class EmployeeWithManagerResourceAssembler extends SimpleRepresentationModelAssembler<EmployeeWithManager> {

	/**
	 * Define links to add to every individual {@link Resource}.
	 *
	 * @param resource
	 */
	@Override
	protected void addLinks(EntityModel<EmployeeWithManager> resource) {

		resource.add(linkTo(methodOn(EmployeeController.class).findDetailedEmployee(resource.getContent().getId())).withSelfRel());
		resource.add(linkTo(methodOn(EmployeeController.class).findOne(resource.getContent().getId())).withRel("summary"));
		resource.add(linkTo(methodOn(EmployeeController.class).findAllDetailedEmployees()).withRel("detailedEmployees"));
	}

	/**
	 * Define links to add to the {@link Resources} collection.
	 *
	 * @param resources
	 */
	@Override
	protected void addLinks(CollectionModel<EntityModel<EmployeeWithManager>> resources) {

		resources.add(linkTo(methodOn(EmployeeController.class).findAllDetailedEmployees()).withSelfRel());
		resources.add(linkTo(methodOn(EmployeeController.class).findAll()).withRel("employees"));
		resources.add(linkTo(methodOn(ManagerController.class).findAll()).withRel("managers"));
		resources.add(linkTo(methodOn(RootController.class).root()).withRel("root"));
	}
}
----

This has a handful of differences from the `ResourceAssembler` objects you've built up to this point:

* Since the routes are different than traditional */employees* and */employees/{id}*, it makes no sense to use `SimpleIdentifiableRepresentationModelAssembler<T>`.
 So instead, you want to fall back to `SimpleRepresentationModelAssembler<EmployeeWithManager>`, in which NO links are defined out of the box.
* Because there are no defined routes, you are in full control.
** `addLinks(EntityModel<EmployeeWithManager> resource)` defines links for single items
** `addLinks(CollectionModel<EntityModel<EmployeeWithManager>> resources)` defines links for collections

In this case, single `EmployeeWithManager` items include a self link to itself, a hop to it's parallel record that only has `Employee` info known as *summary*,
and a link to the detailed collection. To avoid semantic confusion, this is called *detailedEmployees* given *employees* is the common reference to
a collection of summary `Employee` records.

It also makes sense to add links from the other existing REST resources to this detailed `EmployeeWithManager`.

WARNING: Even though `addLinks(CollectionModel<EntityModel<EmployeeWithManager>> resources)` gives you access to a single item's `EntityModel<T>` object,
 it is recommended to NOT manipulate individual item links this way. Instead, use the other method.

Is this the _only_ way to display a detailed record? Not at all. Spring MVC supports request parameters, so it's not that difficult
to code something like this:

[source,java]
----
@GetMapping("/employees/{id}")
public ResponseEntity<?> findOne(@PathVariable long id,
		@RequestParam(value = "detailed", required = false,
		defaultValue = false) boolean detailed) {

	if (detailed) {
		Employee employee = repository.findOne(id);

		return ResponseEntity.ok(
			employeeWithManagerResourceAssembler.toEntityModel(
				new EmployeeWithManager(employee)));
	} else {
		return ResponseEntity.ok(
			assembler.toEntityModel(repository.findOne(id)));
	}
}
----

This type of solution allows serving two different representations from the same URI based on an optional `?detailed=true`
parameter.

There are tradeoffs either way, but this option lends itself to supporting existing routes that you may already have.

To find the other places where detailed `EmployeeWithManager` links have been added, inspect all the `ResourceAssembler` objects
in the example's code base.

== Don't Forget the Root URI

In order to "start at the top" and hop, you must include a `RootController`:

[source,java]
----
@RestController
@RestController
class RootController {

	@GetMapping("/")
	ResponseEntity<RepresentationModel> root() {

		RepresentationModel model = new RepresentationModel();

		model.add(linkTo(methodOn(RootController.class).root()).withSelfRel());
		model.add(linkTo(methodOn(EmployeeController.class).findAll()).withRel("employees"));
		model.add(linkTo(methodOn(EmployeeController.class).findAllDetailedEmployees()).withRel("detailedEmployees"));
		model.add(linkTo(methodOn(ManagerController.class).findAll()).withRel("managers"));

		return ResponseEntity.ok(model);
	}
}
----

Because there is no data at the top, just links, returning back a `ResourceSupport` is perfect. This allows defining all the top links.

And it's easy to go into the various `ResourceAssemblers` and add a link back to the top as needed. It's up to you to see which
bits of hypermedia serve such a link.

== Legacy Routes

What if you started with one set of routes and migrated things to another set? This is the type of scenario that drives people screaming
to version their APIs.

Instead of shouting "don't version APIs" from the rooftops, and appealing to the authority of Roy Fielding, it's better to see
how it's not that hard to support both old and new routes.

For this example, assume that before the `Manager` entity and it's `ManagerController` existed, there was a `Supervisor` with a
matching `SupervisorController`. It had similar data but fewer links. A bit more RPC-like. If the original `Supervisor` entity
was gone, we can add a DTO to represent the old format based on `Manager` like this:

[source,java]
----
/**
 * Legacy representation. Contains older format of data. Fewer links because hypermedia at the time was an after
 * thought.
 *
 * @author Greg Turnquist
 */
@Value
@JsonPropertyOrder({"id", "name", "employees"})
class Supervisor {

	@JsonIgnore
	private final Manager manager;

	public Long getId() {
		return this.manager.getId();
	}

	public String getName() {
		return this.manager.getName();
	}

	public List<String> getEmployees() {
		return manager.getEmployees().stream()
			.map(employee -> employee.getName() + "::" + employee.getRole())
			.collect(Collectors.toList());
	}
}
----

This representation assumes old record had:

* Supervisor's *id*, *name* and a somewhat sloppy display of employee's name and role.
* It's powered by the new `Manager` object, so no need to store multiple copies of data.
* The `Manager` itself is not rendered thanks to the `@JsonIgnore` annotation.

To honor the old route (*/supervisors/{id}*), create a new controller:

[source,java]
----
/**
 * Represent an older controller that has since been replaced with {@link ManagerController}.
 * This controller is used to provide legacy routes, i.e. backwards compatibility.
 *
 * @author Greg Turnquist
 */
@RestController
public class SupervisorController {

	private final ManagerController controller;

	public SupervisorController(ManagerController controller) {
		this.controller = controller;
	}

	@GetMapping("/supervisors/{id}")
	public ResponseEntity<EntityModel<Supervisor>> findOne(@PathVariable Long id) {

		EntityModel<Manager> managerResource = controller.findOne(id).getBody();
		EntityModel<Supervisor> supervisorResource = EntityModel.of(
			new Supervisor(managerResource.getContent()),
			managerResource.getLinks());

		return ResponseEntity.ok(supervisorResource);
	}
}
----

In this example, the assumption is that there was a route for individual supervisors, but not a link for a collection.
This controller has that route, and serves up a `EntityModel<Supervisor>` record. But instead of fetching the data directly,
it leverages the `ManagerController`.

Is that a good idea or a bad idea?

Again, there are tradeoffs. This example is meant to illustrate other options. In this case, leveraging `ManagerController`
allows all links to be generated courtesy of the `ManagerResourceAssembler`. When a `ResponseEntity<EntityModel<Manager>>` object
is returned by the controller, its wrapped REST resource is extracted by Spring MVC's `getBody()` method.

A new `Supervisor` REST resource is constructed by injecting the `Manager` into a `Supervisor` DTO. The provided links are
then copied into that `EntityModel<Supervisor>` object.

Hence, this controller will respond to calls for */supervisors/{id}*, but provide links onto the new system should the client
want to gracefully start migrating.

IMPORTANT: This example also assumes the clients can handle new links as long as the legacy ones are also there. For
a different scenario, that assumption can be adjusted.

With this amount of linking between related objects and DTOs, it's easy to see how Spring HATEOAS can be used to model
a link-driven API. And with the flexible nature of REST, more links can be added in the future along with additional representations.
As long as the existing links are maintained, clients can have a much easier path of migration.
