with - Spring MVC, REST, y HATEOAS
spring mvc angular 4 (4)
Estoy teniendo problemas con la forma correcta de implementar los servicios RESTful de Spring MVC 3.x con HATEOAS . Considere las siguientes restricciones:
- No quiero que mis entidades de dominio estén contaminadas con construcciones web / rest.
- No quiero que mis controladores estén contaminados con construcciones de vista.
- Quiero soportar múltiples vistas.
Actualmente tengo una aplicación MVC muy bien preparada sin HATEOAS. Las entidades de dominio son POJO puros sin ningún concepto de vista o web / resto integrado. Por ejemplo:
class User {
public String getName() {...}
public String setName(String name) {...}
...
}
Mis controladores también son simples. Proporcionan enrutamiento y estado, y delegan en el marco de resolución de vista de Spring. Tenga en cuenta que mi aplicación es compatible con JSON, XML y HTML, sin embargo, ninguna entidad de dominio o controlador tiene información de vista incrustada:
@Controller
@RequestMapping("/users")
class UserController {
@RequestMapping
public ModelAndView getAllUsers() {
List<User> users = userRepository.findAll();
return new ModelAndView("users/index", "users", users);
}
@RequestMapping("/{id}")
public ModelAndView getUser(@PathVariable Long id) {
User user = userRepository.findById(id);
return new ModelAndView("users/show", "user", user);
}
}
Entonces, ahora mi problema: no estoy seguro de una manera limpia de apoyar a HATEOAS. Aquí hay un ejemplo. Digamos que cuando el cliente solicita un Usuario en formato JSON, sale así:
{
firstName: "John",
lastName: "Smith"
}
Digamos también que cuando admito HATEOAS, quiero que JSON contenga un enlace "auto" simple que el cliente puede usar para actualizar el objeto, eliminarlo o algo más. También podría tener un enlace de "amigos" que indique cómo obtener la lista de amigos del usuario:
{
firstName: "John",
lastName: "Smith",
links: [
{
rel: "self",
ref: "http://myserver/users/1"
},
{
rel: "friends",
ref: "http://myserver/users/1/friends"
}
]
}
De alguna manera quiero adjuntar enlaces a mi objeto. Siento que el lugar correcto para hacer esto es en la capa del controlador, ya que todos los controladores conocen las URL correctas. Además, dado que admito varias vistas, creo que lo correcto es decorar de alguna manera mis entidades de dominio en el controlador antes de que se conviertan a JSON / XML / lo que sea en el marco de resolución de vistas de Spring. Una forma de hacerlo podría ser envolver el POJO en cuestión con una clase de recursos genérica que contenga una lista de enlaces. Se necesitarían algunos ajustes de vista para procesarlos en el formato que quiero, pero es factible. Desafortunadamente, los recursos anidados no se pueden envolver de esta manera. Otras cosas que me vienen a la mente incluyen agregar enlaces a ModelAndView y luego personalizar cada uno de los resolvedores de vista listos para usar de Spring para rellenar enlaces en el JSON / XML / etc generado. Lo que no quiero es estar constantemente elaborando a mano JSON / XML / etc. para dar cabida a varios enlaces a medida que van y vienen durante el curso del desarrollo.
¿Pensamientos?
Hay un proyecto útil llamado spring-hateoas en GitHub que tiene la siguiente descripción:
"Este proyecto proporciona algunas API para facilitar la creación de representaciones REST que siguen el principio de HATEOAS cuando se trabaja con Spring y especialmente con Spring MVC"
Si la clase de recurso que está devolviendo se extiende a ''ResourceSupport'', puede agregarle enlaces fácilmente y puede crear enlaces usando ''ControllerLinkBuilder'', por ejemplo, para agregar un enlace propio:
import static org.sfw.hateoas.mvc.ControllerLinkBuilder.*;
Link link = linkTo(YourController.class).slash(resource.getName()).withSelfRel();
resource.add(link);
Es un proyecto bastante nuevo, pero está disponible en el repositorio público de Maven si es necesario:
<dependency>
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
<version>0.3.0.RELEASE</version>
</dependency>
Si usas el artefacto maven:
org.sfw.hateoas.mvc.ControllerLinkBuilder
se convierte en:
org.springframework.hateoas.mvc.ControllerLinkBuilder
Mis pensamientos:
- utilizando algún tipo de convención de nomenclatura para que, por ejemplo, la url de referencia automática se pueda construir a partir del nombre de clase del objeto.
- No creo que el controlador deba agregar las cosas de los enlaces (por cierto, usted mismo escribió "No quiero que mis controladores se contaminen con construcciones de vista". Intentaría buscar una forma de extender la serialización JSON para que pueda agregue automáticamente las cosas adicionales. Es posible que necesite agregar algunas anotaciones a sus entidades, incluso si esto las contamina un poco.
Para crear el enlace en su API REST
, puede utilizar el proyecto HAETOAS
de Spring framework.
org.springframework.hateoas.mvc.ControllerLinkBuilder
clase org.springframework.hateoas.mvc.ControllerLinkBuilder
tiene un conjunto de métodos que puede utilizar para crear un enlace como:
Link link=linkTo(PersonControllerImpl.class).slash(null).withSelfRel();
Además, si tiene un método de controlador que tenga una anotación @RequestMapping
con algún valor URI -
@RequestMapping(value = "/customer", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<?> getCustomer() {
//...
}
entonces puede crear un enlace usando el valor URI del método como
linkTo(methodOn(PersonControllerImpl.class).getCustomer()).toUri().toString()
devolverá String
valor de String
( http://www.urhost.com/customer
) que puede establecer en su Object
entity
.
Simplemente encontré esto mientras buscaba otra cosa y pensé que debería considerar usar el encabezado de enlace en lugar del contenido en el cuerpo de JSON, que en realidad solo contamina las representaciones de sus recursos.
Consulte la nota de IETF sobre enlaces web y también el registro de relaciones de enlaces de la IANA .