В настоящее время я пишу REST API в node.js, используя петлю IBM. Я столкнулся с проблемой, когда порядок наблюдателей имеет значение, и они вызываются в неправильном порядке.
В моей модели Ticket есть поле внутренний статус. Этот статус хранится в базе данных как UUID. Где-то в большом файле «метаданных» также определяется человеческое имя для каждого статуса. То же самое касается поля внешний статус.
Вот соответствующие части Ticket.json
:
{
"name": "Ticket",
"properties": {
"internalStatusId": {
"type": "String"
},
"externalStatusId": {
"type": "String"
}
}
}
Я написал общий миксин, который может преобразовать человеческое имя такого поля UUID в правильный UUID. Этот миксин позволяет клиентам устанавливать поле UUID по его имени (через поле с другим именем).
Вот упрощенная версия миксина:
// 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
не присутствует в аргументах, поэтому внешний статус не установлен. - Во-вторых, вызывается миксин-наблюдатель. Внутреннее имя статуса преобразуется в идентификатор.
Этот порядок, вероятно, вызван тем, что петля сначала загружает наблюдателей в Ticket.js
, а затем наблюдателей миксина.
Я мог бы, конечно, изменить второго наблюдателя, чтобы он искал поля internalStatusId
и internalStatusName
. Однако это приводит к значительному дублированию кода, особенно потому, что у меня много таких наблюдателей бизнес-логики, а также много таких полей UUID.
Я искал способ сообщить loopback, в каком порядке запускать этих наблюдателей. Даже такая простая функция, как Model.observeFirst()
(на самом деле ее не существует!), чтобы поместить одного или нескольких наблюдателей в начало цепочки, решит эту проблему. . Я не смог найти, возможно ли это, и если да, то как.
Как бы вы решили эту проблему?