= Spring HATEOAS - Basic Example

This guides shows a core example of using Spring HATEOAS. It illustrates how to sew hypermedia into your Spring MVC application, including test.

Start with a very simple example, a payroll system that tracks employees.

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
@JsonIgnoreProperties(ignoreUnknown = true)
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(PROTECTED)` - Lombok annotation to create an empty constructor call to appease JPA, but which is protected and not usable to our app's code.
* `@AllArgsConstructor` - Lombok annotation to create an all-arg constructor for certain test scenarios
* `@JsonIgnoreProperties(ignoreUnknown=true)` - Jackson annotation to ignore unknown attributes when deserializing JSON.

NOTE: Make your REST resources robust by instructing Jackson to ignore unknown attributes. That way, additional elements,
like hypermedia (HAL *_links*, HAL-Forms *_templates*, etc.) and newer attributes will be discarded.

This means a HAL document like this:

----
{
	"firstName": "Frodo",
	"lastName": "Baggins",
	"role" : "ring bearer",
	"_links" : {
		"self" : {
			"href" : "/employees/1"
		}
	}
}
----

...which was served up as hypermedia, can be POST'd to create a new employee. The *_links* will simply be ignored.

== 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 information on _how_ to
retrieve and update that information.

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

IMPORTANT: Spring HATEOAS's `EntityModel` 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.

A common convention is to create a factory used to convert `Employee` objects into `EntityModel<Employee>` objects. Spring
HATEOAS provides `SimpleIdentifiableRepresentationModelAssembler<T>` as the simplest mechanism to perform these conversions.

[source,java]
----
@Component
class EmployeeRepresentationModelAssembler extends SimpleIdentifiableRepresentationModelAssembler<Employee> {

	/**
	 * Link the {@link Employee} domain type to the {@link EmployeeController} using this
	 * {@link SimpleIdentifiableRepresentationModelAssembler} in order to generate both {@link org.springframework.hateoas.EntityModel}
	 * and {@link org.springframework.hateoas.CollectionModel}.
	 */
	EmployeeRepresentationModelAssembler() {
		super(EmployeeController.class);
	}
}
----

This class has two key properties:

* The generic type (`Employee`) declares the entity type.
* The constructor defines the Spring MVC controller (`EmployeeController`) where links are found to turn the entity into a REST resource.

The class is flagged with Spring's `@Component` annotation so that it will be automatically hooked into the
application context.

This is half the battle, already solved. This resource assembler is used _in the controller_ to assemble REST resources, as shown in the next section.

== Creating Links

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;
	private final EmployeeRepresentationModelAssembler assembler;

	EmployeeController(EmployeeRepository repository, EmployeeRepresentationModelAssembler assembler) {

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

	...

}
----

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

To support `SimpleIdentifiableRepresentationModelAssembler`, the controller needs two things:

* A route to the collection. By default, it assumes a pluralized, lowercased name (`Employee` -> `/employees`).
* A route to a single entity. By default it assumes the collection's URI + `/{id}`.

The collection's route is shown below:

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

}
----

It uses the `EmployeeRepresentationModelAssembler` and it's `toCollectionModel(Iterable<Employee>)` method to turn a collection of
`Employee` objects into a `CollectionModel<EntityModel<Employee>>`.

NOTE: `CollectionModel` 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 using
 * {@link EmployeeRepresentationModelAssembler#toEntityModel(Object)}. Then return it through
 * Spring Web's {@link ResponseEntity} fluent API.
 *
 * @param id
 */
@GetMapping("/employees/{id}")
public ResponseEntity<EntityModel<Employee>> findOne(@PathVariable long id) {
	return this.repository.findById(id) //
            .map(this.assembler::toModel) //
            .map(ResponseEntity::ok) //
            .orElse(ResponseEntity.notFound().build());
}
----

Again, the `EmployeeRepresentationModelAssembler` is used to convert a single `Employee` into a `EntityModel<Employee>`
through its `toEntityModel(Employee)` method.

== Customizing the Output

What's not shown in this example is that the `EmployeeRepresentationModelAssembler` comes with overrides.

* `setBasePath(/* base */)` would inject a prefix into every link built in the hypermedia.
* `addLinks(EntityModel<T>)` and `addLinks(CollectionModel<T>)` allows you to override/augment the default links assigned to every resource.
* `getCollectionLinkBuilder()` lets you override the convention of how the whole route is built up.

== 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)
@Import({EmployeeRepresentationModelAssembler.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.
* `@Import({EmployeeRepresentationModelAssembler.class})` pulls in one extra Spring component that would be ignored by `@WebMvcTest`.
* `@Autowired MockMvc` gives us a handle on a Spring Mock tester.
* `@MockBean` flags `EmployeeRepositor` as a test collaborator.

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_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.
** Verify that the JSON Path of *$._embedded.employees[0].id* is `1`.

The rest of the assertions are not shown above, 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].