java - generic - jira rest api authentication
API REST: ¿DTO o no? (4)
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 los mixins de Jackson 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?
Por qué deberías usar DTO en tu 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
@XmlTransient
y@JsonIgnore
para evitar la serialización de algunos atributos. -
Al utilizar 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 usar las anotaciones
@ApiModel
y@ApiModelProperty
para documentar sus modelos de API sin alterar 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. Al usar Spring HATEOAS , puede hacer que sus clases de DTO extiendan
ResourceSupport
o las envuelvan conResource<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 puede considerar
Lombok
para generar métodos getters, setters,
equals()
,
hashcode()
y
toString()
para usted.
Relacionado: Para dar mejores nombres a sus clases de DTO, consulte esta answer .
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 por todo el código repetitivo que necesita.
Esto es principalmente cierto para el lado de respuesta de una API json / rest. 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.
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.
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 generar 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 deberían 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.