HATEOAS REST API和域驱动设计,在哪里放置工作流逻辑?

时间:2015-05-24 14:50:30

标签: rest domain-driven-design hateoas hypermedia

这是作为RESTful API: Where should I code my workflow?的后续问题。问题的简短摘要(适合我的问题更好)将是这样的:

每个域对象都包含与特定有界上下文(X)中的特定对象关联的业务逻辑。 REST API包含将查询或命令的结果转换为通过线路发送的数据的逻辑(例如JSON)。当使用HATEOAS和超媒体时,我们希望使用链接建模资源之间的关系。但是为了确定REST API应该返回哪些链接,通常需要求助于业务逻辑/规则。问题是,这些“工作流程规则”属于DDD应用程序的位置?他们是否可能处于一个不同的有限环境中,只处理工作流规则(可能是与X的“伙伴”式关系),还是属于X BC?

3 个答案:

答案 0 :(得分:0)

我不是DDD专家(在Eric Evan的书中只有100页),但我可以告诉你我们的电子商务目录中发生了什么。

最初我们在基于数据的应用程序的相同有限上下文中有这样的业务流程和请求用户的角色/权限我们改变了状态转换(你说链接,但这真的是它的核心,链接只是呈现给用户的状态转换的一种方式。这工作正常,但是执行了很多重复的逻辑。然后我们添加了一个搜索应用程序,它是一个不同的有界上下文,因为它呈现相同的数据但是在不同的集合/分组中,我们并不想让它们不同步。

我们转向CQRS实施,因此我们的许多业务逻辑都是预先计算好的"因此,它就像是一个伴随的合作伙伴环境"作为从写模型到阅读模型的投影的一部分。我们没有专门存储链接,而是标记允许的数据行为。目录应用程序和搜索应用程序都使用此读取模型及其行为标志来确定要呈现给客户端的状态转换。

有些东西在请求资源时动态发生,几乎在序列化步骤中。我们已经将这些目标尽可能地转移到预先计算的位置,但我们无法预先计算(仅仅因为规模)是专门针对用户的内容。与推荐的搜索一样,它使用搜索引擎中的BI数据来返回结果。我们可以为每个用户预先计算,但这些数字对我们的系统来说太大了。因此,我们发送主要应用程序计算资源(来自主要上下文)并将其传递给另一个合作伙伴上下文以进一步细化。

另一个用例是某些链接仅提供给经过身份验证的用户,因此对匿名用户是隐藏的。我们在主要的应用程序环境中执行此操作,但它开始变得有点障碍,因为它们的存在表明请求后面的用户可以在其他应用程序中执行的操作(例如更改密码),并且我们的上下文不是'真的是用户可以在其他应用程序中执行的权限。将资源交给其上下文并让它们在我们将其返回给用户之前处理它会更好。我们用于此的一个简单解决方案是,不是深层链接到外部上下文中的函数,而是链接到该上下文的根资源并允许它呈现状态转换。这意味着有2个请求,但它会清除逻辑的位置/权限。

答案 1 :(得分:0)

工作流实际上由领域知识和仇恨基础设施组成。

如果应用程序不是使用超媒体设计的,那么您甚至可能不需要hateoas部分。但是领域知识仍然存在,他们只是生活在最终用户中。头脑。您需要领域知识来验证用户的命令,以防它们忘记它。

因此,对于hateoas,我将工作流实现分为两部分:域模型和hateoas基础结构。

域名模型告诉域知识 另一方面,hateoas基础设施是hateoas特定的,将它们排除在域外。

这是一个使用springframework-hateoas的java示例。我将工作流程放在将域模型映射到资源的过程中。

@Component
public class OrderResourceAssembler extends ResourceAssemblerSupport<Order, OrderResource> {

    @Override
    public OrderResource toResource(Order model) {

        OrderResource resource = mapToResource(model);
        resource.add(orderResourceHref(model).withSelfRel());//add self link
        if (model.isAvailableToCancel()) { //let the model tell
            //add cancel link
            resource.add(orderResourceHref(model).withRel("cancel")); 
        }
        if (model.isAvailableToPay()) { //let the model tell
            //add payment link
            resource.add(new Link("http://www.restfriedchicken.com/online-txn/" + model.getTrackingId(), "payment")); 
        }
        //etc


        return resource;
    }
    // omitted codes
}

如果模型无法自行判断,您可以引入规范对象来完成工作。

答案 2 :(得分:0)

资源所在的位置是需要编组访问权限的相同位置。

假设您拥有一个拥有三个有限背景的更大系统:员工管理,客户接纳和服务供应。

从员工管理中获取员工的信息?决定是否显示可用于POST或DELETE角色的链接是由员工管理决定的。

从客户入场处获得新提交的服务合同?决定是否显示可用于提升修订版或POST后续详细信息的链接是供客户决定。当然,员工管理层主持分发处理新服务合同所必需的角色,但客户入口负责了解需要哪些索赔和其他条件,并最终确保一切都结束。

同样,从服务配置中获取物理安装的软件配置文件?服务供应需要确保在发布链接之前,所有内容都与其他服务/上下文(付费客户的帐户,网络服务角色中的当前用户,设备未被锁定以进行维护)保持一致您可以在哪里提供新的服务质量规格。

这些&#39;工作流程&#39;决策是每个背景的组成部分 - 它们不应该在其他地方分开。