REST API - 是否使用DTO?[已关闭]
REST API - 是否使用DTO?[已关闭]
已关闭。这个问题是基于观点的。目前不接受回答。
想改进这个问题? 更新这个问题使其能够通过事实和引用回答。
改进这个问题
我目前正在为一个项目创建REST-API,并一直在阅读有关最佳实践的文章。许多人似乎反对DTO,只是暴露领域模型,而另一些人似乎认为DTO(或用户模型或任何你想称之为的东西)是不好的实践。就个人而言,我觉得这篇文章很有道理。
然而,我也理解DTO的缺点,包括所有额外的映射代码、与其DTO对应物可能百分之百相同的领域模型等。
我们的API主要是为其他客户端消费数据而创建的,然而,如果我们做得正确,我们也希望在可能的情况下将其用于我们自己的Web GUI。
问题是,我们可能不希望向其他客户端用户公开所有领域数据。许多数据只在我们自己的Web应用程序中有意义。此外,在所有情况下,我们可能不想公开有关对象的所有数据,特别是与其他对象的关系等。例如,如果我们公开特定对象的列表,我们不一定希望公开整个对象层次结构。因此,对象的子级不会被公开,但可以通过链接(HATEOAS)发现。
我应该如何解决这个问题?我在思考在我们的域模型上使用Jackson mixins来控制在不同场景下公开哪些数据。还是我们应该一直使用DTO - 即使它有缺点和争议?
为什么你应该在你的REST API中使用DTOs
DTO代表Data Transfer Object。
这一模式具有非常明确定义的目的:传输数据到远程界面,就像Web服务一样。这一模式非常适合REST API,使用DTOs将在长远来看给你更多的灵活性。
表示应用程序域的模型与表示API处理的数据的模型是(或至少应该是)不同的问题,并且应该相互解耦。您不希望在应用程序域模型中添加、删除或重命名字段时破坏API客户端。
当您的服务层操作域/持久性模型时,您的API控制器应该操作不同的模型集。当您的域/持久性模型发展到支持新的业务要求时,例如,您可能希望创建新版本的API模型以支持这些变化。随着新版本的推出,您可能还希望取消旧版本的API。这是完全可能的,当这些事情相互解耦时。
只是提一下使用DTOs暴露而不是持久性模型的一些好处:
-
将持久性模型从API模型中解耦。
-
DTOs可以根据您的需求定制,并且当仅公开持久性实体的一组属性时非常有用。您不需要使用
@XmlTransient
和@JsonIgnore
等注释来避免一些属性的序列化。 -
使用DTOs可以避免您的持久性实体中的注释过多,也就是说,您的持久性实体不会因非持久性相关注释而变得臃肿。
-
在创建或更新资源时,您将完全控制您接收到的属性。
-
如果您正在使用Swagger,您可以使用
@ApiModel
和@ApiModelProperty
注释来记录您的API模型,而不会影响您的持久性实体。 -
您可以为每个API版本使用不同的DTOs。
-
在映射关系时,您将拥有更多的灵活性。
-
您可以为不同的媒体类型使用不同的DTOs。
-
您的DTOs可以有一个链接列表,用于HATEOAS。这种事情不应该添加到持久对象中。当使用Spring HATEOAS时,您可以使您的DTO类扩展
RepresentationModel
(以前称为ResourceSupport
)或使用EntityModel
(以前称为Resource
)来包装它们。
处理模板代码
您将不需要手动将您的持久性实体映射到DTOs,反之亦然。有许多映射框架可以用来完成此操作。例如,看看基于注释的MapStruct,它作为Maven注释处理器工作。它在基于CDI和Spring的应用程序中都能很好地工作。
你也可以考虑使用Lombok来为你生成getter,setter,equals()
,hashcode()
和toString()
方法。
相关:要为你的DTO类取更好的名称,请参考这个答案。