REST API - DTO或不是?
我想在微服务的背景下重新提出这个问题。这是原始问题的引用。
我目前正在为一个项目创建一个REST-API并且一直在阅读
关于最佳做法的文章。许多人似乎反对
DTO只是公开域模型,而其他人似乎
认为DTO(或用户模型或任何你想要称之为的东西)都很糟糕
实践。就个人而言,我认为这篇文章很有意义。
但是,我也理解DTO的所有额外的缺点
映射代码,可能与其完全100%相同的域模型
DTO-pair等。
现在,我的问题
我更倾向于在我的应用程序的所有层中使用一个Object(换句话说,只是暴露域对象而不是创建DTO并手动复制每个字段)。我可以使用Jackson注释来解决合同与代码之间的差异 @JsonIgnore
要么 @JsonProperty(access = Access.WRITE_ONLY)
要么 @JsonView
等等)。或者如果有一个或两个字段需要使用Jackson Annotation无法完成的转换,那么我将编写自定义逻辑来处理这个问题(相信我,在我5年多的时间里,我甚至都没有遇到过这种情况休息服务的长途旅行)
我想知道我是否遗漏了没有将域复制到DTO的任何真正的不良影响
如果您使用CQRS,决定会更简单,因为:
- 对于您使用的写入方
Commands
已经是DTO的; Aggregates
- 域层中的丰富行为对象 - 不会被公开/查询,因此没有问题。
- 对于读取方,因为您使用了薄层,从持久性中提取的对象应该已经是DTO。应该没有映射问题,因为你可以有一个
readmodel
对于每个用例。在最坏的情况下,您可以使用GraphQL之类的东西来仅选择您需要的字段。
如果不将读取与写入分开,则决策更难,因为两种解决方案都存在权衡。
公开域对象的优点
- 编写的代码越少,产生的错误就越少。
- 尽管在我们的代码库中有广泛的(可论证的)测试用例,但由于错过/错误地将字段从域复制到DTO或反之,我遇到了错误。
- 可维护性 - 减少锅炉板代码。
- 如果我必须添加一个新属性,我当然不必添加Domain,DTO,Mapper和testcases。不要告诉我这可以使用反射beanCopy utils来实现,它打败了整个目的。
- 龙目岛,Groovy,Kotlin我知道,但它只会让我得到安慰者头痛。
- 干
- 性能
- 我知道这属于“过早的性能优化是万恶之源”的范畴。但是这仍然可以节省一些CPU周期,而不必每次请求创建(以及后来的垃圾收集)一个或多个对象(至少)
缺点
- 从长远来看,DTO将为您提供更大的灵活性
- 如果我只需要那种灵活性。至少,到目前为止我遇到的是CRUD对http的操作,我可以使用@JsonIgnores来管理。或者,如果有一个或两个字段需要使用Jackson Annotation无法完成的转换,正如我之前所说,我可以编写自定义逻辑来处理这个问题。
- 域对象因注释而变得臃肿。
- 这是一个有效的问题。如果我使用JPA或MyBatis作为我的持久框架,域对象可能会有这些注释,那么也会有Jackson注释。在我的情况下,这不太适用,但我使用Spring启动,我可以通过使用应用程序范围的属性,如
mybatis.configuration.map-underscore-to-camel-case: true
, spring.jackson.property-naming-strategy: SNAKE_CASE
短篇故事至少在我的情况下,缺点并不比专业人士好,所以通过新的POJO作为DTO重复自己是没有任何意义的。代码减少,错误机会减少。因此,继续公开Domain对象而没有单独的“view”对象。
放弃:这可能适用于您的用例,也可能不适用。这个观察是根据我的用例(基本上是一个有15个端点的CRUD api)