为什么域模型不应该用作REST API中的资源?

时间:2015-11-28 11:21:17

标签: api rest domain-driven-design domain-model

我发现一个声明,即根据DDD设计的域模型不应该用作REST API(source)中的资源。

很明显,REST API是应用程序的契约,而域模型是实现的一部分,因此最好将这两个事物分开,这样域模型的更改不会自动暗示REST API中的更改。

但是,我想如果是小型项目(REST API只有一个消费者 - 由一个团队开发的javascript前端),拥有单独模型的好处并不能证明分离模型的成本是合理的(不同的类 - 域模型和资源表示以及模型之间的映射代码)。显然,域层不能引用REST特定的基础结构代码(以保持关注点分离)。

域名和REST模型应该分开吗?

5 个答案:

答案 0 :(得分:10)

使用DDD时,应始终将REST API与域模型分开。

这样做的主要原因是简化 - 您不希望通过API向客户端泄漏域模型的复杂性。否则,客户需要了解您的域的细微差别和复杂性,这很可能使API难以使用。

使用DDD的主要驱动因素是一个复杂的问题域,所以这总是一个问题。

  

但是,我认为在小型项目(...)的情况下,使用单独模型的好处并不能证明分离模型的成本(......)。

我同意有些项目的分离域模型和REST API过度工程化。但是,这些案例不适合DDD,因为您不会从DDD中获益足以证明其成本合理。

答案 1 :(得分:5)

  

为什么域模型不应该用作REST API中的资源?

因为网络与核心域层完全不同。您的实体中的方法特别难以翻译,因为HTTP只有少量动词。如果您想通过REST公开您的应用程序,您必须将您的域进程窃取到HTTP中,这通常意味着做出妥协并设计与您的域实体不同的资源。

当然,如果你正在做HATEOAS,你应该在HTTP客户端和服务器之间以及域应用协议中交换的消息中找到无处不在语言中的术语,但是网络必然会扭曲你的域表示。

REST的重点不是重新创建域及其进程的高保真模型,而是以符合HTTP的方式提供它们,同时尽可能少地丢失转换。但它仍然是一种翻译。

答案 2 :(得分:1)

我认为需要考虑的另一件事是谁使用您的REST API。如果您正在开发应用程序的前端,那么您可以说一切仍然在1个有限的上下文中发生。只有一部分存在于客户端/ javascript中。在这种情况下,我认为在你的休息api中公开你的模型是有意义的。

在这种情况下,REST api可能只是与您的域服务进行通信的一种方式,例如。

答案 3 :(得分:1)

您可以根据域模型将业务逻辑挂钩到REST资源中。例如,每当有人设置is_published = 1时,您可以通过挂钩事件或变更器来通知管理员,进行额外验证等。有时事情可能过于复杂和奇怪,因此您可以将某些属性标记为不可修改,然后创建自定义操作来修改您公开的属性,如果这有意义的话。我认为,如果你设计得当,你甚至不需要这些“自定义动作”。 Facebook没有使用任何我认为没有的Graph API。我正在考虑开发一个基于暴露模型层的框架,我仍然认为这是一个好主意。

答案 4 :(得分:1)

我认为REST API的主要好处是为(通常是服务器端而非SPA)第三方REST客户端提供服务。如果您使用HATEOAS和其他自描述消息解决方案(如RDF),则REST客户端会由于REST API的更改而更加难以破解。对于小型项目-“ REST API只有一个使用者-一个团队开发的javascript前端” -我认为拥有适当的REST API并不值得。大多数人都使用它的简化版本,我将其称为CRUD API,这可能对这些项目有用。

CRUD资源与贫血域模型的域对象之间可以存在一对一的映射。如果我们不仅仅使用CRUD方法谈论真实的对象(而不是数据结构),那么您必须在resource.verb和object.method之间进行转换,例如:

POST /dogs/{id}/barking
 -> domain.dog.bark()

如果我们要讨论涉及多个域对象和工作单元(事务)的更复杂的事物,那么您需要为应用程序服务添加另一层,否则您将把包括事务处理在内的整个复杂操作移至客户端。在这种情况下,您可以在resource.verb和applicationService.operation之间进行转换,例如:

POST /dogs/{id1,id2,..}/barking
 -> dogService.multiDogBark(...)
 -> UnitOfWork{domain.dogs[ids[i]].bark()}

我认为大多数开发人员都会将此CRUD服务+贫乏域模型方法与REST服务+域模型方法混淆,这就是为什么要问这个问题,这就是为什么有很多“ REST”框架会添加1:1域对象的原因-CRUD资源映射甚至ORM实体-CRUD资源映射。我发现这种趋势极具破坏性,我认为主要原因是开发人员只能从短文章或问答站点中肤浅地学习某些技术,而不是阅读可以使他们对实际主题有深入了解的书籍和论文。我认为这是一个Y +代问题,由于使用数字技术,我们正在失去阅读长篇文章的能力。我们的条件是即时获得奖励,而不是冗长的文字给出的延迟奖励...