= Spring HATEOAS - Basic Example

This guides shows how to add Spring HATEOAS in the simplest way possible. Like the rest of these examples, it uses a payroll system.

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

== Defining Your Domain

The cornerstone of any example is the domain object:

[source,java]
----
@Data
@Entity
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor
class Employee {

	@Id @GeneratedValue
	private Long id;
	private String firstName;
	private String lastName;
	private String role;

	...
}
----

This domain object includes:

* `@Data` - Lombok annotation to define a mutable value object
* `@Entity` - JPA annotation to make the object storagable in a classic SQL engine (H2 in this example)
* `@NoArgsConstructor(PRIVATE)` - Lombok annotation to create an empty constructor call to appease Jackson, but which is private and not usable to our app's code.
* `@AllArgsConstructor` - Lombok annotation to create an all-arg constructor for certain test scenarios

== Accessing Data

To experiment with something realistic, you need to access a real database. This example leverages H2, an embedded JPA datasource.
And while it's not a requirement for Spring HATEOAS, this example uses Spring Data JPA.

Create a repository like this:

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

This interface extends Spring Data Commons' `CrudRepository`, inheriting a collection of create/replace/update/delete (CRUD)
operations.

[[converting-entities-to-resources]]
== Converting Entities to Resources

In REST, the "thing" being linked to is a *resource*. Resources provide both information as well as details on _how_ to
retrieve and update that information.

Spring HATEOAS defines a generic `EntityModel<T>` container that lets you store any domain object (`Employee` in this example), and
add additional links.

IMPORTANT: Spring HATEOAS's `Resource` and `Link` classes are *vendor neutral*. HAL is thrown around a lot, being the
default media type, but these classes can be used to render any media type.

The following Spring MVC controller defines the application's routes, and hence is the source of links needed
in the hypermedia.

NOTE: This guide assumes you already somewhat familiar with Spring MVC.

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

	private final EmployeeRepository repository;

	EmployeeController(EmployeeRepository repository) {
		this.repository = repository;
	}

	...
}
----

This piece of code shows how the Spring MVC controller is wired with a copy of the `EmployeeRepository` through
constructor injection and marked as a *REST controller* thanks to the `@RestController` annotation.

The route for the https://martinfowler.com/bliki/DDD_Aggregate.html[aggregate root] is shown below:

[source,java]
----
/**
 * Look up all employees, and transform them into a REST collection resource.
 * Then return them through Spring Web's {@link ResponseEntity} fluent API.
 */
@GetMapping("/employees")
ResponseEntity<CollectionModel<EntityModel<Employee>>> findAll() {

	List<EntityModel<Employee>> employees = StreamSupport.stream(repository.findAll().spliterator(), false)
		.map(employee -> EntityModel.of(employee,
			linkTo(methodOn(EmployeeController.class).findOne(employee.getId())).withSelfRel(),
			linkTo(methodOn(EmployeeController.class).findAll()).withRel("employees")))
		.collect(Collectors.toList());

	return ResponseEntity.ok(
		CollectionModel.of(employees,
			linkTo(methodOn(EmployeeController.class).findAll()).withSelfRel()));
}
----

It retrieves a collection of `Employee` objects, streams through a Java 8 spliterator, and converts them into a collection
of `EntityModel<Employee>` objects by using Spring HATEOAS's `linkTo` and `methodOn` helpers to build links.

* The natural convention with REST endpoints is to serve a *self* link (denoted by the `.withSelfRel()` call).
* It's also useful for any single item resource to include a link back to the aggregate (denoted by the `.withRel("employees")`).

The whole collection of single item resources is then wrapped in a Spring HATEOAS `Resources` type.

NOTE: `Resources` is Spring HATEOAS's vendor neutral representation of a collection. It has it's
own set of links, separate from the links of each member of the collection. That's why the whole
structure is `CollectionModel<EntityModel<Employee>>` and not `CollectionModel<Employee>`.

To build a single resource, the `/employees/{id}` route is shown below:

[source,java]
----
/**
 * Look up a single {@link Employee} and transform it into a REST resource. Then return it through
 * Spring Web's {@link ResponseEntity} fluent API.
 *
 * @param id
 */
@GetMapping("/employees/{id}")
ResponseEntity<EntityModel<Employee>> findOne(@PathVariable long id) {

	return repository.findById(id)
		.map(employee -> EntityModel.of(employee,
			linkTo(methodOn(EmployeeController.class).findOne(employee.getId())).withSelfRel(),
			linkTo(methodOn(EmployeeController.class).findAll()).withRel("employees")))
		.map(ResponseEntity::ok)
		.orElse(ResponseEntity.notFound().build());
}
----

This code is almost identical. It fetches a single item `Employee` from the database and that wraps up into a
`EntityModel<Employee>` object with the same links, but that's it. No need to create a `Resources` object since is NOT a
collection.

IMPORTANT: Does this look like duplicate code found in the aggregate root? Sures it does. That's why Spring HATEOAS
 includes the ability to define a `ResourceAssembler`. It lets you define, in one place, all the links for a given
 entity type. Then you can reuse it as needed in all relevant controller methods. It's been left out of this section
 for the sake of simplicity.

== Testing Hypermedia

Nothing is complete without testing. Thanks to Spring Boot, it's easier than ever to test a Spring MVC controller,
including the generated hypermedia.

The following is a bare bones "slice" test case:

[source,java]
----
@RunWith(SpringRunner.class)
@WebMvcTest(EmployeeController.class)
public class EmployeeControllerTests {

	@Autowired
	private MockMvc mvc;

	@MockBean
	private EmployeeRepository repository;

	...
}
----

* `@RunWith(SpringRunner.class)` is needed to leverage Spring Boot's test annotations with JUnit.
* `@WebMvcTest(EmployeeController.class)` confines Spring Boot to only autoconfiguring Spring MVC components, and _only_
this one controller, making it a very precise test case.
* `@Autowired MockMvc` gives us a handle on a Spring Mock tester.
* `@MockBean` flags `EmployeeRepository` as a test collaborator, since we don't plan on talking to a real database in this test case.

With this structure, we can start crafting a test case!

[source,java]
----
@Test
public void getShouldFetchAHalDocument() throws Exception {

	given(repository.findAll()).willReturn(
		Arrays.asList(
			new Employee(1L,"Frodo", "Baggins", "ring bearer"),
			new Employee(2L,"Bilbo", "Baggins", "burglar")));

	mvc.perform(get("/employees").accept(MediaTypes.HAL_JSON_VALUE))
		.andDo(print())
		.andExpect(status().isOk())
		.andExpect(header().string(HttpHeaders.CONTENT_TYPE, MediaTypes.HAL_JSON_UTF8_VALUE))
		.andExpect(jsonPath("$._embedded.employees[0].id", is(1)))
	...
}
----

* At first, the test case uses Mockito's `given()` method to define the "given"s of the test.
* Next, it uses Spring Mock MVC's `mvc` to `perform()` a *GET /employees* call with an accept header of HAL's media type.
* As a courtesy, it uses the `.andDo(print())` to give us a complete print out of the whole thing on the console.
* Finally, it chains a whole series of assertions.
** Verify HTTP status is *200 OK*.
** Verify the response *Content-Type* header is also HAL's media type (with UTF-8 flavor).
** Verify that the JSON Path of *$._embedded.employees[0].id* is `1`.
** And so forth...

The rest of the assertions are commented out, but you can read it in the source code.

NOTE: This is not the only way to assert the results. See Spring Framework reference docs and Spring HATEOAS
test cases for more examples.

For the next step in Spring HATEOAS, you may wish to read link:../api-evolution[Spring HATEOAS - API Evolution Example].