API REST: ¿DTO o no? [cerrado]

154

Actualmente estoy creando una REST-API para un proyecto y he estado leyendo artículo tras artículo sobre las mejores prácticas. Muchos parecen estar en contra de los DTO y simplemente exponen el modelo de dominio, mientras que otros parecen pensar que los DTO (o modelos de usuario o como quieran llamarlo) son una mala práctica. Personalmente, pensé que este artículo tenía mucho sentido.

Sin embargo, también entiendo los inconvenientes de los DTO con todo el código de mapeo adicional, los modelos de dominio que podrían ser 100% idénticos a su contraparte DTO, etc.

Nuestra API se crea principalmente para que otros clientes puedan consumir datos, sin embargo, si lo hacemos bien, también nos gustaría usarlo para nuestra propia GUI web si es posible.

La cuestión es que es posible que no queramos exponer todos los datos del dominio a los otros usuarios del cliente. Gran parte de los datos solo tendrán sentido en nuestra propia aplicación web. Además, es posible que no queramos exponer todos los datos sobre un objeto en todos los escenarios, especialmente las relaciones con otros objetos, etc. Por ejemplo, si exponemos una lista de un objeto en particular, no necesariamente queremos exponer toda la jerarquía de objetos; para que los hijos del objeto no estén expuestos, sino que se puedan descubrir a través de enlaces (hateoas).

¿Cómo debo resolver este problema? Estaba pensando en usar Jackson mixins en nuestros modelos de dominio para controlar qué datos estarían expuestos en diferentes escenarios. ¿O deberíamos usar DTO todo el tiempo, incluso teniendo en cuenta sus inconvenientes y controversia?

benbjo
fuente
9
No se sorprenda si esta pregunta se cierra. Es más una pregunta basada en la discusión, lo que significa que no hay una respuesta correcta clara. Pregunte a diferentes personas y obtendrá una respuesta diferente.
Ben Thurley
2
El enlace de ese artículo ( ibm.com/developerworks/community/blogs/barcia/entry/… ) está roto.
pinkpanther
77
@pinkpanther Ese es un gran artículo y es una pena que ya no esté disponible. Aquí está la versión en caché de Web Archive .
cassiomolin

Respuestas:

251

¿Por qué debería usar DTO en su API REST?

DTO significa D ata T ransfer O bject .

Este patrón fue creado con un propósito muy bien definido: transferir datos a interfaces remotas , al igual que los servicios web . Este patrón encaja muy bien en una API REST y los DTO le darán más flexibilidad a largo plazo.

Los modelos que representan el dominio de su aplicación y los modelos que representan los datos manejados por su API son (o al menos deberían ser) preocupaciones diferentes y se deben desacoplar entre sí. No desea romper sus clientes API cuando agrega, elimina o cambia el nombre de un campo del modelo de dominio de la aplicación.

Mientras que su capa de servicio opera sobre los modelos de dominio / persistencia, sus controladores API deberían operar sobre un conjunto diferente de modelos. A medida que sus modelos de dominio / persistencia evolucionan para admitir nuevos requisitos comerciales, por ejemplo, es posible que desee crear nuevas versiones de los modelos API para admitir estos cambios. También es posible que desee desaprobar las versiones anteriores de su API a medida que se lanzan nuevas versiones. Y es perfectamente posible lograrlo cuando las cosas están desacopladas.


Solo por mencionar algunos beneficios de exponer los DTO en lugar de los modelos de persistencia:

  • Desacoplar modelos de persistencia de modelos API.

  • Los DTO se pueden adaptar a sus necesidades y son excelentes cuando exponen solo un conjunto de atributos de sus entidades de persistencia. No necesitará anotaciones como @XmlTransienty @JsonIgnorepara evitar la serialización de algunos atributos.

  • Al usar DTO, evitará un montón de anotaciones en sus entidades de persistencia, es decir, sus entidades de persistencia no se hincharán con anotaciones relacionadas con la no persistencia.

  • Tendrá control total sobre los atributos que recibe al crear o actualizar un recurso.

  • Si está utilizando Swagger , puede utilizar @ApiModely @ApiModelPropertyanotaciones para documentar sus modelos API sin ensuciar sus entidades de persistencia.

  • Puede tener diferentes DTO para cada versión de su API.

  • Tendrá más flexibilidad al mapear relaciones.

  • Puede tener diferentes DTO para diferentes tipos de medios.

  • Sus DTO pueden tener una lista de enlaces para HATEOAS . Ese es el tipo de cosas que no deberían agregarse a los objetos de persistencia. Cuando use Spring HATEOAS , puede hacer que sus clases de DTO se extiendan RepresentationModel(anteriormente conocido como ResourceSupport) o envolverlas EntityModel(anteriormente conocido como Resource<T>).

Tratar con el código repetitivo

No necesitará asignar sus entidades de persistencia a DTO y viceversa de forma manual . Hay muchos marcos de mapeo que puede usar para hacerlo. Por ejemplo, eche un vistazo a MapStruct , que está basado en anotaciones y funciona como un procesador de anotaciones Maven. Funciona bien en aplicaciones CDI y basadas en Spring.

También es posible que desee considerar Lombok para generar captadores equals(), establecedores hashcode()y toString()métodos para usted.


Relacionado: Para dar mejores nombres a sus clases de DTO, consulte esta respuesta .

cassiomolin
fuente
2
Si siguiera el camino DTO, ¿asignaría todos los objetos de dominio a un DTO o solo los que no serían idénticos? Además, ¿cómo resolvería el problema de exponer datos basados ​​en diferentes escenarios / contextos? ¿Múltiples DTO por objeto de dominio?
benbjo
66
@benbjo Depende de usted. Por lo general, solo asigno las entidades más complejas a los DTO, las entidades a las que no quiero tener expuestos todos los atributos y las entidades con muchas relaciones. Los DTO me dan la flexibilidad de tener una lista de enlaces para usar en HATEOAS. Ese es el tipo de cosas que no agregaría a mis objetos de persistencia.
cassiomolin
2
@molin muchas gracias por la información y sugerencias. Definitivamente voy a revisar MapStruct. De un vistazo parece que se adapta muy bien a mis necesidades.
benbjo
66
Estimado votante, ¿podría al menos explicar la razón de su voto negativo?
cassiomolin
8
También hay una razón arquitectónica para usar DTO en lugar de entidades de dominio en la API REST. La API REST no debe cambiar para evitar romper clientes existentes. Si usa el modelo de dominio directamente en la API, crea un acoplamiento no deseado entre la API y el modelo de dominio. Según el principio de diseño del Acoplamiento suelto del servicio, el contrato de servicio no debe estar estrechamente relacionado con la lógica del servicio o los detalles de implementación.
Paulo Merson
25

Cuando su API es pública y debe admitir varias versiones, debe elegir DTO.

Por otro lado, si es una API privada y usted controla tanto el cliente como el servidor, tiendo a omitir los DTO y exponer directamente el modelo de dominio.

David Siro
fuente
Estoy de acuerdo con usted en la última parte y generalmente lo hago, pero esta es mi primera API pública. Consideraré lo que dices sobre el uso de DTO para la parte pública. Tal vez las partes privadas y públicas de la API deberían estar separadas, incluso si "comer su propio alimento para perros" es un buen principio.
benbjo
11

Tiendo a usar DTO.

No me gustan los inconvenientes, pero parece que las otras opciones son aún peores:

La exposición de objetos de dominio puede conducir a problemas de seguridad y pérdida de datos. Las anotaciones de Jackson pueden parecer resolver el problema, pero es demasiado fácil cometer un error y exponer datos que no deben exponerse. Al diseñar una clase DTO es mucho más difícil cometer tal error.

Por otro lado, los inconvenientes del enfoque DTO se pueden reducir con cosas como el mapeo de objeto a objeto y Lombok por menos repetitivo.

Argb32
fuente
9

Como ya lo dijo, esta es claramente una pregunta relacionada con la opinión. Yo mismo me siento más atraído por el enfoque No-DTO, simplemente debido a todo el código repetitivo que necesita.

Esto es principalmente cierto para el lado de respuesta de una json / rest api. Incluso escribí un complemento de Jackson para evitar escribir muchas vistas / filtros json para estos casos: https://github.com/Antibrumm/jackson-antpathfilter

Por otro lado, los DTO son algo bueno en el lado de entrada de solicitud de tales API. Trabajar directamente en entidades puede ser bastante difícil teniendo en cuenta las relaciones bidireccionales, por ejemplo. Además, realmente no desea permitir que una persona que llama modifique un atributo "creador", por ejemplo. Por lo tanto, deberá anular ciertos campos durante el mapeo de tales solicitudes.

Martin Frey
fuente
2
Estoy de acuerdo en que mi pregunta está algo relacionada con la opinión (y desanimada), sin embargo, también estaba buscando consejos sobre cómo resolver mi problema. Tomaré mucho en su complemento de Jackson, sin embargo, ¿cree que usar mixins para controlar qué datos deben exponerse en diferentes escenarios es una buena opción?
benbjo