mvc example spring rest spring-data domain-driven-design spring-data-rest

example - spring rest controller file upload



¿Es problemático que Spring Data REST exponga las entidades a través de recursos REST sin usar DTO? (3)

tl; dr

No. Los DTO son solo uno de los medios para desacoplar el modelo de dominio del lado del servidor de la representación expuesta en los recursos HTTP. También puede utilizar otros medios de desacoplamiento, que es lo que Spring Data REST hace.

Detalles

Sí, Spring Data REST inspecciona el modelo de dominio que tiene en el lado del servidor para razonar sobre la forma en que se verán las representaciones de los recursos que expone. Sin embargo, aplica un par de conceptos cruciales que mitigan los problemas que traería una exposición ingenua de objetos de dominio.

Spring Data REST busca agregados y, de forma predeterminada, configura las representaciones en consecuencia.

El problema fundamental con el ingenuo "lanzo mis objetos de dominio frente a Jackson" es que, desde el modelo de entidad simple, es muy difícil razonar acerca de los límites de representación razonables. Especialmente los modelos de entidad derivados de tablas de base de datos tienen el hábito de conectar prácticamente todo a todo. Esto se debe al hecho de que conceptos de dominio importantes como agregados simplemente no están presentes en la mayoría de las tecnologías de persistencia (leer: especialmente en bases de datos relacionales).

Sin embargo, yo diría que en este caso el "No exponga su modelo de dominio" actúa más sobre los síntomas de eso que sobre el núcleo del problema. Si diseña su modelo de dominio correctamente, existe una gran superposición entre lo que es beneficioso en el modelo de dominio y cómo se ve una buena representación para conducir efectivamente ese modelo a través de los cambios de estado. Un par de reglas simples:

  • Para cada relación con otra entidad, pregúntese: ¿no podría esto ser una referencia de identificación? Al usar una referencia de objeto, usted arrastra una gran cantidad de semántica del otro lado de la relación a su entidad. Solucionar esto generalmente lleva a las entidades a referirse a entidades que se refieren a entidades, lo cual es un problema en un nivel más profundo. En el nivel de representación, esto le permite cortar datos, atender ámbitos de consistencia, etc.
  • Evite las relaciones bidireccionales, ya que son muy difíciles de conseguir en el lado de la actualización de las cosas.

Spring Data REST hace varias cosas para transferir esas relaciones de entidad a los mecanismos adecuados en el nivel HTTP: enlaces en general y, lo que es más importante, enlaces a recursos dedicados que administran esas relaciones. Lo hace mediante la inspección de los repositorios declarados para las entidades y, básicamente, reemplaza una incorporación de la entidad relacionada que, de lo contrario, sería necesaria, con un enlace a un recurso de asociación que le permite administrar esa relación explícitamente.

Ese enfoque usualmente funciona bien con las garantías de consistencia descritas por los agregados de DDD en el nivel HTTP. PUT solicitudes PUT no abarcan múltiples agregados de forma predeterminada, lo cual es bueno ya que implica un alcance de coherencia del recurso que coincide con los conceptos de su dominio.

No tiene sentido forzar a los usuarios a DTO si ese DTO simplemente duplica los campos del objeto de dominio.

Puede introducir tantos DTO para sus objetos de dominio como desee. En la mayoría de los casos, los campos capturados en el objeto de dominio se reflejarán de alguna manera en la representación. Todavía tengo que ver al Customer la entidad que contiene un nombre, un nombre y emailAddress propiedad de dirección de emailAddress , y que son completamente irrelevantes en la representación.

La introducción de DTO no garantiza un desacoplamiento de ninguna manera. He visto demasiados proyectos en los que se introdujeron por motivos de cultivo de carga, simplemente duplicé todos los campos de la entidad que los respaldaba y, por lo tanto, causó un esfuerzo adicional porque cada campo nuevo también debía agregarse a los DTO. ¡Pero oye, desacoplamiento! No. ¯ / _ (ツ) _ / ¯

Dicho esto, por supuesto, hay situaciones en las que querría modificar ligeramente la representación de esas propiedades, especialmente si utiliza objetos de valor fuertemente tipados para, por ejemplo, una dirección de EmailAddress (¡bien!) Pero aún así desea representar esto como una String simple en JSON . Pero de ninguna manera es un problema: Spring Data REST usa a Jackson debajo de las coberturas, lo que le ofrece una amplia variedad de medios para modificar la representación: anotaciones, combinaciones para mantener las anotaciones fuera de sus tipos de dominio, serializadores personalizados, etc. capa de mapeo en el medio.

No usar DTO por defecto no es algo malo per se. ¡Imagínese la indignación de los usuarios sobre la cantidad de repetición necesaria si exigiéramos que se escribieran DTO para todo! Un DTO es solo un medio para un fin. Si ese fin se puede lograr de una manera diferente (y generalmente se puede), ¿por qué insistir en los DTO?

Simplemente no use Spring Data REST donde no se ajuste a sus requisitos.

Continuando con los esfuerzos de personalización, vale la pena notar que Spring Data REST existe para cubrir exactamente las partes de la API, que solo sigue los patrones básicos de implementación de la API REST que implementa. Y esa funcionalidad está en su lugar para darle más tiempo para pensar

  1. Cómo dar forma a tu modelo de dominio
  2. Qué partes de su API se expresan mejor a través de interacciones impulsadas por hipermedia.

Aquí hay una diapositiva de la charla que di en la Plataforma SpringOne 2016 que resume la situación.

La cubierta de diapositivas completa se puede encontrar here . También hay una grabación de la charla disponible en InfoQ.

Spring Data REST existe para que puedas concentrarte en los círculos subrayados. De ninguna manera creemos que se puede crear una gran API realmente solo activando Spring Data REST. Solo queremos reducir la cantidad de repetitivo para que tenga más tiempo para pensar en los bits interesantes.

Al igual que Spring Data, en general, reduce la cantidad de código repetitivo que se escribirá para las operaciones de persistencia estándar. Nadie diría que se puede construir una aplicación del mundo real solo a partir de las operaciones de CRUD. Sin embargo, eliminando el esfuerzo de las partes aburridas, le permitimos que piense más intensamente sobre los desafíos del dominio real (y en realidad debería hacerlo).

Puede ser muy selectivo al anular ciertos recursos para tomar el control completo de su comportamiento, incluido el mapeo manual de los tipos de dominio a los DTO, si así lo desea. También puede colocar una funcionalidad personalizada junto a lo que Spring Data REST proporciona y simplemente enganchar los dos. Sea selectivo sobre lo que usa.

Una muestra

Puede encontrar un ejemplo ligeramente avanzado de lo que describí en Spring RESTBucks , una implementación basada en Spring (Data REST) ​​del ejemplo de RESTBucks en el libro RESTful Web Services. Utiliza Spring Data REST para administrar las instancias de Order , pero modifica su manejo para introducir requisitos personalizados e implementar completamente la parte de pago de la historia manualmente.

En mi experiencia limitada, me han dicho repetidas veces que no debe pasar las entidades al frente o por medio del descanso, sino que debe usar un DTO.

¿Spring Data Rest no hace exactamente esto? He analizado brevemente las proyecciones, pero parece que solo limitan los datos que se devuelven, y aún esperan que una entidad como parámetro para un método de envío se guarde en la base de datos. ¿Me estoy perdiendo algo aquí, o soy yo (y mis compañeros de trabajo) incorrectos en el sentido de que nunca deben pasar por alto y ser una entidad?


Solíamos utilizar DTO, incluidas las capas totalmente tradicionales (base de datos, DTO, repositorio, servicio, controladores, ...) para cada entidad en nuestros proyectos. Saltar los DTOs algún día salvará nuestra vida :)

Entonces, para una entidad de City simple que tiene id,name,country,state , hicimos lo siguiente:

  1. Tabla de la City con id,name,county,.... columnas
  2. CityDTO con id,name,county,.... propiedades (exactamente igual que la base de datos)
  3. CityRepository con un findCity(id),....
  4. CityService con findCity(id) { CityRepository.findCity(id) }
  5. CityController con findCity(id) { ConvertToJson( CityService.findCity(id)) }

Demasiados códigos repetitivos para exponer la información de la ciudad al cliente. Como se trata de una entidad simple, no se hacen negocios en todas estas capas, solo pasan los objetos. Un cambio en la entidad City comenzaba desde la base de datos y cambiaba todas las capas. (Por ejemplo, agregar una propiedad de location , bueno porque al final la propiedad de location debe estar expuesta al usuario como json ). Al agregar un método findByNameAndCountryAllIgnoringCase , es necesario cambiar todas las capas (cada capa debe tener un nuevo método).

Considerando Spring Data Rest ( of course with Spring Data ) ¡esto es más que simple!

public interface CityRepository extends CRUDRepository<City, Long> { City findByNameAndCountryAllIgnoringCase(String name, String country); }

La entidad de la city está expuesta al cliente con un código mínimo y aún así usted tiene control sobre cómo se expone la ciudad. Validation , Security , Object Mapping ... está todo allí. Así que puedes pellizcar cada cosa.

Por ejemplo, si quiero mantener al cliente inconsciente sobre el cambio de nombre de propiedad de la entidad de la city (separación de capa), puedo usar el asignador de objetos personalizado mencionado https://docs.spring.io/spring-data/rest/docs/3.0.2.RELEASE/reference/html/#customizing-sdr.custom-jackson-deserialization

Para resumir

Usamos Spring Data Rest tanto como sea posible, en casos de uso complicados todavía podemos recurrir a las capas tradicionales y dejar que el Service y el Controller hagan algunos negocios.


Spring Data REST permite una forma muy rápida de crear prototipos y crear una API REST basada en una estructura de base de datos. Estamos hablando de minutos frente a días, al comparar con otras tecnologías de programación.

El precio que paga por eso, es que su API REST está estrechamente unida a la estructura de su base de datos. A veces, eso es un gran problema. A veces no lo es. Depende básicamente de la calidad del diseño de su base de datos y de su capacidad para cambiarla para que se ajuste a las necesidades de los usuarios de la API.

En resumen, considero Spring Data REST como una herramienta que puede ahorrarle mucho tiempo en ciertas circunstancias especiales. No como una bala de plata que se puede aplicar a cualquier problema.