Polish text.
* Replace "mediatype" with "media type". * Remove usage of "produces" clauses in Spring MVC route definitions, since XML support was removed from Spring HATEOAS.
This commit is contained in:
@@ -5,7 +5,7 @@ image:https://travis-ci.org/spring-projects/spring-hateoas-examples.svg?branch=m
|
||||
This repository contains example projects to interact with Spring HATEOAS.
|
||||
|
||||
* Learn how to interact with a Spring HATEOAS-powered app, from inside as well as the command line.
|
||||
* See how to upgrade a REST resource without having to create new mediatypes, version URIs, etc.
|
||||
* See how to upgrade a REST resource without having to create new media types, version URIs, etc.
|
||||
|
||||
We have separate folders for each of these:
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ is not detailed.
|
||||
|
||||
You can use content negotation to discover what HTTP verbs are supported. And you can take a shot at supplying properties
|
||||
based on existing data records. But the beauty of REST is that by not having a single megaspec, you can adjust and adapt
|
||||
by adopting new mediatypes. HAL has been well received, but perhaps there is something better?
|
||||
by adopting new media types. HAL has been well received, but perhaps there is something better?
|
||||
|
||||
HAL-FORMS, an extension of HAL, attempts to bridge this gap. It supports HAL's lightweight of concept of data and links,
|
||||
but introduces another element, *_templates*. *_templates* make it possible to show all the operations possible as well as
|
||||
@@ -178,7 +178,7 @@ it's wrapped as a `Resource` with links added to itself and to the aggregate roo
|
||||
* Buried in both endpoints is the new `.andAffordance()` API. Instead of `linkTo()`, you instead use the `afford()` API
|
||||
to show related information.
|
||||
|
||||
Affordances is about chaining related links together to support richer mediatypes. In this case, Spring HATEOAS has HAL-FORMS support. This means
|
||||
Affordances is about chaining related links together to support richer media types. In this case, Spring HATEOAS has HAL-FORMS support. This means
|
||||
you can connect the *GET* link to its related *POST* link using the `andAffordance(afford(methodOn(...))`. A given link can
|
||||
also connect to multiple affordances. That's why this example also shows linking to the `deleteEmployee` endpoint as well.
|
||||
|
||||
@@ -277,7 +277,7 @@ To round out this controller, you must also code the `deleteEmployee()` operatio
|
||||
This operation is quite simple. It deletes based upon *id* then returns an `HTTP 204 No Content` response.
|
||||
|
||||
Our controller has been made more sophisticated by linking related operations together. However, to take advantage of this,
|
||||
you must shift gears and use a different hypermedia-based mediatype. This demands on additional step. By default, Spring
|
||||
you must shift gears and use a different hypermedia-based media type. This demands on additional step. By default, Spring
|
||||
Boot sets things up for HAL. To switch to HAL-FORMS, you need to create this:
|
||||
|
||||
[source,java]
|
||||
@@ -393,7 +393,7 @@ This template data is enough information for you to generate an HTML form on a w
|
||||
IMPORTANT: Spring HATEOAS doesn't provide the JavaScript to do this. This hypermedia format, though, has all the information you need to create it yourself. Or deploy somebody's
|
||||
3rd party library that speaks HAL-FORMS.
|
||||
|
||||
Are you wondering why Spring HATEOAS doesn't simply render an HTML form straight up? There are other mediatypes designed
|
||||
Are you wondering why Spring HATEOAS doesn't simply render an HTML form straight up? There are other media types designed
|
||||
for this, especially XHTML. Using the Affordances API, we plan to add support in the future, allowing you to negotiate
|
||||
for the format you prefer.
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ Start by adding a *root node* for clients to start from. The idea is to find rel
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@GetMapping(value = "/", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/")
|
||||
public ResourceSupport root() {
|
||||
|
||||
ResourceSupport rootResource = new ResourceSupport();
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.springframework.hateoas.examples;
|
||||
|
||||
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.*;
|
||||
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.hateoas.Resources;
|
||||
@@ -43,7 +42,7 @@ class EmployeeController {
|
||||
this.assembler = assembler;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/")
|
||||
public ResourceSupport root() {
|
||||
|
||||
ResourceSupport rootResource = new ResourceSupport();
|
||||
@@ -55,7 +54,7 @@ class EmployeeController {
|
||||
return rootResource;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/employees", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees")
|
||||
public Resources<Resource<Employee>> findAll() {
|
||||
return assembler.toResources(repository.findAll());
|
||||
}
|
||||
@@ -72,7 +71,7 @@ class EmployeeController {
|
||||
.orElse(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
@GetMapping(value = "/employees/{id}", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees/{id}")
|
||||
public ResponseEntity<Resource<Employee>> findOne(@PathVariable Long id) {
|
||||
|
||||
return repository.findById(id)
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.springframework.hateoas.examples;
|
||||
|
||||
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.*;
|
||||
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.hateoas.Resources;
|
||||
@@ -43,7 +42,7 @@ class EmployeeController {
|
||||
this.assembler = assembler;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/")
|
||||
public ResourceSupport root() {
|
||||
|
||||
ResourceSupport rootResource = new ResourceSupport();
|
||||
@@ -55,7 +54,7 @@ class EmployeeController {
|
||||
return rootResource;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/employees", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees")
|
||||
public Resources<Resource<Employee>> findAll() {
|
||||
return assembler.toResources(repository.findAll());
|
||||
}
|
||||
@@ -72,7 +71,7 @@ class EmployeeController {
|
||||
.body(assembler.toResource(savedEmployee));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/employees/{id}", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees/{id}")
|
||||
public Resource<Employee> findOne(@PathVariable Long id) {
|
||||
return repository.findById(id)
|
||||
.map(assembler::toResource)
|
||||
|
||||
@@ -89,7 +89,7 @@ Spring HATEOAS defines a generic `Resource<T>` container that lets store any dom
|
||||
add additional links.
|
||||
|
||||
IMPORTANT: Spring HATEOAS's `Resource` and `Link` classes are *vendor neutral*. HAL is thrown around a lot, being the
|
||||
default mediatype, but these classes can be used to render any mediatype.
|
||||
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 `Resource<Employee>` objects. Spring
|
||||
HATEOAS provides `SimpleIdentifiableResourceAssembler<T>` as the simplest mechanism to perform these conversions.
|
||||
@@ -162,12 +162,8 @@ The collection's route is shown below:
|
||||
* Look up all employees, and transform them into a REST collection resource using
|
||||
* {@link EmployeeResourceAssembler#toResources(Iterable)}. Then return them through
|
||||
* Spring Web's {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* NOTE: cURL will fetch things as HAL JSON directly, but browsers issue a different
|
||||
* default accept header, which allows XML to get requested first, so "produces"
|
||||
* forces it to HAL JSON for all clients.
|
||||
*/
|
||||
@GetMapping(value = "/employees", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees")
|
||||
public ResponseEntity<Resources<Resource<Employee>>> findAll() {
|
||||
return ResponseEntity.ok(
|
||||
assembler.toResources(repository.findAll()));
|
||||
@@ -191,11 +187,9 @@ To build a single resource, the `/employees/{id}` route is shown below:
|
||||
* {@link EmployeeResourceAssembler#toResource(Object)}. Then return it through
|
||||
* Spring Web's {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* See {@link #findAll()} to explain {@link GetMapping}'s "produces" argument.
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
@GetMapping(value = "/employees/{id}", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees/{id}")
|
||||
public ResponseEntity<Resource<Employee>> findOne(@PathVariable long id) {
|
||||
return ResponseEntity.ok(
|
||||
assembler.toResource(repository.findOne(id)));
|
||||
@@ -266,11 +260,11 @@ public void getShouldFetchAHalDocument() throws Exception {
|
||||
----
|
||||
|
||||
* 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 mediatype.
|
||||
* 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 mediatype.
|
||||
** 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 commented out, but you can read it in the source code.
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.hateoas.examples;
|
||||
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.Resources;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -47,15 +46,12 @@ class EmployeeController {
|
||||
* Look up all employees, and transform them into a REST collection resource using
|
||||
* {@link EmployeeResourceAssembler#toResources(Iterable)}. Then return them through
|
||||
* Spring Web's {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* NOTE: cURL will fetch things as HAL JSON directly, but browsers issue a different
|
||||
* default accept header, which allows XML to get requested first, so "produces"
|
||||
* forces it to HAL JSON for all clients.
|
||||
*/
|
||||
@GetMapping(value = "/employees", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees")
|
||||
public ResponseEntity<Resources<Resource<Employee>>> findAll() {
|
||||
|
||||
return ResponseEntity.ok(
|
||||
assembler.toResources(repository.findAll()));
|
||||
this.assembler.toResources(this.repository.findAll()));
|
||||
|
||||
}
|
||||
|
||||
@@ -64,15 +60,13 @@ class EmployeeController {
|
||||
* {@link EmployeeResourceAssembler#toResource(Object)}. Then return it through
|
||||
* Spring Web's {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* See {@link #findAll()} to explain {@link GetMapping}'s "produces" argument.
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
@GetMapping(value = "/employees/{id}", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees/{id}")
|
||||
public ResponseEntity<Resource<Employee>> findOne(@PathVariable long id) {
|
||||
|
||||
return repository.findById(id)
|
||||
.map(assembler::toResource)
|
||||
return this.repository.findById(id)
|
||||
.map(this.assembler::toResource)
|
||||
.map(ResponseEntity::ok)
|
||||
.orElse(ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
@@ -143,12 +143,8 @@ class ManagerController {
|
||||
* Look up all managers, and transform them into a REST collection resource using
|
||||
* {@link ManagerResourceAssembler#toResources(Iterable)}. Then return them through
|
||||
* Spring Web's {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* NOTE: cURL will fetch things as HAL JSON directly, but browsers issue a different
|
||||
* default accept header, which allows XML to get requested first, so "produces"
|
||||
* forces it to HAL JSON for all clients.
|
||||
*/
|
||||
@GetMapping(value = "/managers", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/managers")
|
||||
ResponseEntity<Resources<Resource<Manager>>> findAll() {
|
||||
return ResponseEntity.ok(
|
||||
assembler.toResources(repository.findAll()));
|
||||
@@ -160,11 +156,9 @@ class ManagerController {
|
||||
* {@link ManagerResourceAssembler#toResource(Object)}. Then return it through
|
||||
* Spring Web's {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* See {@link #findAll()} to explain {@link GetMapping}'s "produces" argument.
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
@GetMapping(value = "/managers/{id}", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/managers/{id}")
|
||||
ResponseEntity<Resource<Manager>> findOne(@PathVariable long id) {
|
||||
return ResponseEntity.ok(
|
||||
assembler.toResource(repository.findOne(id)));
|
||||
@@ -182,7 +176,7 @@ With the basic routes defined, you could say we have an operational REST service
|
||||
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 mediatypes they are represented in. The paradigm of REST is
|
||||
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*
|
||||
@@ -202,7 +196,7 @@ class EmployeeController {
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(value = "/managers/{id}/employees", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/managers/{id}/employees")
|
||||
public ResponseEntity<Resources<Resource<Employee>>> findEmployees(@PathVariable long id) {
|
||||
return ResponseEntity.ok(
|
||||
assembler.toResources(repository.findByManagerId(id)));
|
||||
@@ -318,7 +312,7 @@ To support this, we can write the corresponding route in `EmployeeController`:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@GetMapping(value = "/employees/detailed", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees/detailed")
|
||||
public ResponseEntity<Resources<Resource<EmployeeWithManager>>> findAllDetailedEmployees() {
|
||||
|
||||
return ResponseEntity.ok(
|
||||
@@ -328,7 +322,7 @@ public ResponseEntity<Resources<Resource<EmployeeWithManager>>> findAllDetailedE
|
||||
.collect(Collectors.toList())));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/employees/{id}/detailed", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees/{id}/detailed")
|
||||
public ResponseEntity<Resource<EmployeeWithManager>> findDetailedEmployee(@PathVariable Long id) {
|
||||
|
||||
Employee employee = repository.findOne(id);
|
||||
@@ -403,7 +397,7 @@ to code something like this:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@GetMapping(value = "/employees/{id}", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees/{id}")
|
||||
public ResponseEntity<?> findOne(@PathVariable long id,
|
||||
@RequestParam(value = "detailed", required = false,
|
||||
defaultValue = false) boolean detailed) {
|
||||
@@ -527,7 +521,7 @@ public class SupervisorController {
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/supervisors/{id}", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/supervisors/{id}")
|
||||
public ResponseEntity<Resource<Supervisor>> findOne(@PathVariable Long id) {
|
||||
|
||||
Resource<Manager> managerResource = controller.findOne(id).getBody();
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.hateoas.examples;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.Resources;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -48,12 +47,8 @@ class EmployeeController {
|
||||
* Look up all employees, and transform them into a REST collection resource using
|
||||
* {@link EmployeeResourceAssembler#toResources(Iterable)}. Then return them through
|
||||
* Spring Web's {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* NOTE: cURL will fetch things as HAL JSON directly, but browsers issue a different
|
||||
* default accept header, which allows XML to get requested first, so "produces"
|
||||
* forces it to HAL JSON for all clients.
|
||||
*/
|
||||
@GetMapping(value = "/employees", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees")
|
||||
public ResponseEntity<Resources<Resource<Employee>>> findAll() {
|
||||
return ResponseEntity.ok(
|
||||
assembler.toResources(repository.findAll()));
|
||||
@@ -65,11 +60,9 @@ class EmployeeController {
|
||||
* {@link EmployeeResourceAssembler#toResource(Object)}. Then return it through
|
||||
* Spring Web's {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* See {@link #findAll()} to explain {@link GetMapping}'s "produces" argument.
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
@GetMapping(value = "/employees/{id}", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees/{id}")
|
||||
public ResponseEntity<Resource<Employee>> findOne(@PathVariable long id) {
|
||||
|
||||
return repository.findById(id)
|
||||
@@ -84,13 +77,13 @@ class EmployeeController {
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(value = "/managers/{id}/employees", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/managers/{id}/employees")
|
||||
public ResponseEntity<Resources<Resource<Employee>>> findEmployees(@PathVariable long id) {
|
||||
return ResponseEntity.ok(
|
||||
assembler.toResources(repository.findByManagerId(id)));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/employees/detailed", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees/detailed")
|
||||
public ResponseEntity<Resources<Resource<EmployeeWithManager>>> findAllDetailedEmployees() {
|
||||
|
||||
return ResponseEntity.ok(
|
||||
@@ -100,7 +93,7 @@ class EmployeeController {
|
||||
.collect(Collectors.toList())));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/employees/{id}/detailed", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees/{id}/detailed")
|
||||
public ResponseEntity<Resource<EmployeeWithManager>> findDetailedEmployee(@PathVariable Long id) {
|
||||
|
||||
return repository.findById(id)
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.hateoas.examples;
|
||||
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.Resources;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -42,12 +41,8 @@ class ManagerController {
|
||||
* Look up all managers, and transform them into a REST collection resource using
|
||||
* {@link ManagerResourceAssembler#toResources(Iterable)}. Then return them through
|
||||
* Spring Web's {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* NOTE: cURL will fetch things as HAL JSON directly, but browsers issue a different
|
||||
* default accept header, which allows XML to get requested first, so "produces"
|
||||
* forces it to HAL JSON for all clients.
|
||||
*/
|
||||
@GetMapping(value = "/managers", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/managers")
|
||||
ResponseEntity<Resources<Resource<Manager>>> findAll() {
|
||||
return ResponseEntity.ok(
|
||||
assembler.toResources(repository.findAll()));
|
||||
@@ -59,11 +54,9 @@ class ManagerController {
|
||||
* {@link ManagerResourceAssembler#toResource(Object)}. Then return it through
|
||||
* Spring Web's {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* See {@link #findAll()} to explain {@link GetMapping}'s "produces" argument.
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
@GetMapping(value = "/managers/{id}", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/managers/{id}")
|
||||
ResponseEntity<Resource<Manager>> findOne(@PathVariable long id) {
|
||||
|
||||
return repository.findById(id)
|
||||
@@ -78,7 +71,7 @@ class ManagerController {
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(value = "/employees/{id}/manager", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees/{id}/manager")
|
||||
ResponseEntity<Resource<Manager>> findManager(@PathVariable long id) {
|
||||
return ResponseEntity.ok(
|
||||
assembler.toResource(repository.findByEmployeesId(id)));
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.hateoas.examples;
|
||||
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -37,7 +36,7 @@ public class SupervisorController {
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/supervisors/{id}", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/supervisors/{id}")
|
||||
public ResponseEntity<Resource<Supervisor>> findOne(@PathVariable Long id) {
|
||||
|
||||
Resource<Manager> managerResource = controller.findOne(id).getBody();
|
||||
|
||||
@@ -59,7 +59,7 @@ Spring HATEOAS defines a generic `Resource<T>` container that lets you store any
|
||||
add additional links.
|
||||
|
||||
IMPORTANT: Spring HATEOAS's `Resource` and `Link` classes are *vendor neutral*. HAL is thrown around a lot, being the
|
||||
default mediatype, but these classes can be used to render any mediatype.
|
||||
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.
|
||||
@@ -91,12 +91,8 @@ The route for the https://martinfowler.com/bliki/DDD_Aggregate.html[aggregate ro
|
||||
/**
|
||||
* Look up all employees, and transform them into a REST collection resource.
|
||||
* Then return them through Spring Web's {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* NOTE: cURL will fetch things as HAL JSON directly, but browsers issue a different
|
||||
* default accept header, which allows XML to get requested first, so "produces"
|
||||
* forces it to HAL JSON for all clients.
|
||||
*/
|
||||
@GetMapping(value = "/employees", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees")
|
||||
ResponseEntity<Resources<Resource<Employee>>> findAll() {
|
||||
|
||||
List<Resource<Employee>> employees = StreamSupport.stream(repository.findAll().spliterator(), false)
|
||||
@@ -131,11 +127,9 @@ To build a single resource, the `/employees/{id}` route is shown below:
|
||||
* Look up a single {@link Employee} and transform it into a REST resource. Then return it through
|
||||
* Spring Web's {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* See {@link #findAll()} to explain {@link GetMapping}'s "produces" argument.
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
@GetMapping(value = "/employees/{id}", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees/{id}")
|
||||
ResponseEntity<Resource<Employee>> findOne(@PathVariable long id) {
|
||||
|
||||
return repository.findById(id)
|
||||
@@ -207,11 +201,11 @@ public void getShouldFetchAHalDocument() throws Exception {
|
||||
----
|
||||
|
||||
* 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 mediatype.
|
||||
* 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 mediatype (with UTF-8 flavor).
|
||||
** 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...
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.Resources;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -52,12 +51,8 @@ class EmployeeController {
|
||||
/**
|
||||
* Look up all employees, and transform them into a REST collection resource.
|
||||
* Then return them through Spring Web's {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* NOTE: cURL will fetch things as HAL JSON directly, but browsers issue a different
|
||||
* default accept header, which allows XML to get requested first, so "produces"
|
||||
* forces it to HAL JSON for all clients.
|
||||
*/
|
||||
@GetMapping(value = "/employees", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees")
|
||||
ResponseEntity<Resources<Resource<Employee>>> findAll() {
|
||||
|
||||
List<Resource<Employee>> employees = StreamSupport.stream(repository.findAll().spliterator(), false)
|
||||
@@ -92,11 +87,9 @@ class EmployeeController {
|
||||
* Look up a single {@link Employee} and transform it into a REST resource. Then return it through
|
||||
* Spring Web's {@link ResponseEntity} fluent API.
|
||||
*
|
||||
* See {@link #findAll()} to explain {@link GetMapping}'s "produces" argument.
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
@GetMapping(value = "/employees/{id}", produces = MediaTypes.HAL_JSON_VALUE)
|
||||
@GetMapping("/employees/{id}")
|
||||
ResponseEntity<Resource<Employee>> findOne(@PathVariable long id) {
|
||||
|
||||
return repository.findById(id)
|
||||
|
||||
Reference in New Issue
Block a user