定义环回观察者的顺序

时间:2017-05-15 19:02:32

标签: node.js loopback observers

我目前正在使用IBM的环回在node.js中编写REST API。我遇到了一个问题,即观察者的顺序是相关的,并且它们的顺序是错误的。

我的 Ticket 模型具有内部状态字段。此状态作为UUID存储在数据库中。某个地方的大型元数据"文件,还定义了每个状态的人名。 外部状态字段也是如此。

以下是Ticket.json的相关部分:

{
  "name": "Ticket",
  "properties": {
    "internalStatusId": {
      "type": "String"
    },
    "externalStatusId": {
      "type": "String"
    }
  }
}

我编写了一个通用mixin,可以将这样一个UUID字段的人名转换为正确的UUID。此mixin用于允许客户端按名称设置UUID字段(通过不同的命名字段)。

这是mixin的简化版本:

// This observer is actually a simplification of the actual observer,
// which is more generic. It handles "name to id" mapping for any number
// of fields you can configure in the <model>.json file.
Model.observe('before save', function (ctx, next) {
  let data = ctx.isNewInstance ? ctx.instance : ctx.data;
  if (data.internalStatusName) {
    data.internalStatusId = internalStatusNameToIdMap[data.internalStatusName];
    delete data.internalStatusName;
  }
  next();
});

因此,如果您向PUT发送/Tickets/1个请求{ "internalStatusName": "Closed" }作为正文,则此代码会将其转换为正确的UUID,将其放入internalStatusId字段,并从参数中删除internalStatusName字段。

现在,系统中存在业务规则:如果内部状态设置为Closed,则外部状态也需要设置为Closed。其代码位于Ticket.js,因为它不是通用的,只与 Ticket 模型相关:

// This observer is located in Ticket.json.
// It makes sure that, when a ticket's internal status is set to Closed,
// the external status is also set to Closed.
Ticket.observe('before save', function (ctx, next) {
  let data = ctx.isNewInstance ? ctx.instance : ctx.data;
  if (data.internalStatusId === INTERNAL_STATUS_CLOSED_UUID) {
    data.externalStatusId = EXTERNAL_STATUS_CLOSED_UUID;
  }
  next();
});

我遇到的问题是这两个观察者不能很好地协同工作,因为它们是以错误的顺序调用的。

如果我发送{ "internalStatusName": "Closed" }

  • 首先调用来自Ticket.js的观察者。这将检查是否设置了internalStatusId字段,以了解是否需要更新外部状态。参数中不存在internalStatusId,因此未设置外部状态。
  • 其次,调用mixin观察者。内部状态名称将转换为id。

这个顺序可能是由环回首先加载Ticket.js中的观察者以及之后的mixin观察者引起的。

我当然可以修改第二个观察者,以查找internalStatusId internalStatusName字段。但是,这会导致严重的代码重复,特别是因为我有许多这样的业务逻辑观察器以及许多像这样的UUID字段。

我一直在寻找一种方法来告诉loopback运行这些观察者的顺序。甚至像Model.observeFirst()这样的函数(这实际上并不存在!)来放置一个或多个观察者链的前面会解决这个问题。我无法找到这是否可能,如果可行,如何。

你会如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

Loopback首先加载模型的实现,并且仅在mixins的这个实现之后,因此错误的顺序。 Loopback使用标准的事件订阅系统。因此,您可以使用prependListener将侦听器添加到开头。

// Puts first
Model.prependListener('before save', function (ctx, next) {
  let data = ctx.isNewInstance ? ctx.instance : ctx.data;
  if (data.internalStatusName) {
    data.internalStatusId = internalStatusNameToIdMap[data.internalStatusName];
    delete data.internalStatusName;
  }
  next();
});