Integrations
The Integration record defines a specific integration.
Integrations are defined as a sequence of Steps. A Step is used to perform some type of action, such as:
- sending an HTTP request
- database insert, update, or query
- scheduling an event
- data aggregation
When an Integration is triggered, all Steps are evaluated, and Transactions are sequentially created to execute the Step logic. When a Transaction has been completed, a check occurs to see if there is another Step to run. If another Step is identified, a new Transaction will be created to execute the Step logic.
This will continue until the final Step of the Integration has been completed.
Data model
| Field label | Field name | Description |
|---|---|---|
| Name | name | Name of the Integration. |
| Run synchronously | synchronous | If true, this Integration will not be triggered automatically when the condition is matched. It can instead be triggered using the utilities for running synchronous integrations. |
| Application | sys_scope | The scope of the Integration. |
| Active | active | Specifies if the Integration is active. |
| Advanced | advanced | Advanced is used to indicate that the advanced condition should be evaluated. It also makes the advanced condition field visible on the form view. |
| Table | table | The table that is used to trigger the Integration. |
| Operations | operations | The operations that are used to trigger the Integration. |
| Conditions | conditions | The conditions that are used to trigger the Integration. |
| Advanced condition | advanced_condition | Script field that is used to configure an advanced condition. |
TIP
If multiple Integrations exist on the same table, consider having the trigger in a separate scope so it can be reused for all Integrations. Otherwise, the trigger will be bound to one of the Integrations, and all other Integrations will have a dependency on the Integration that owns the trigger.
Triggers
A trigger is a piece of code that calls TransactionUtils.checkIntegrationTriggersAsync() or TransactionUtils.checkIntegrationTriggers(). Usually this code will live inside a Business Rule but it can be defined using other solutions as well. In this documentation we will use Business Rules as an example when discussing Triggers.
In more complex scenarios (such as instances using domain separation), or if you want more direct control, triggers should be created manually.
Disable the Business Rule called Manage integration triggers to stop the automatic trigger management.
All triggers are configured almost identically.
| Field | Value |
|---|---|
| name | im_trigger_<operation> |
| collection | table that the integration runs on. |
| when | most often async_always, but can be configured for synchronous use as well. |
| filter_condition | sys_updated_by!=system^EQ |
| action_insert | create one trigger for each operation the integration runs on. If the integration should run on insert and update, create one trigger for insert and one for update. |
| action_update | create one trigger for each operation the integration runs on. If the integration should run on insert and update, create one trigger for insert and one for update. |
| action_delete | create one trigger for each operation the integration runs on. If the integration should run on insert and update, create one trigger for insert and one for update. |
| advanced | true |
| script | see example below |
| sys_scope | select which scope is appropriate according to your setup. |
| sys_domain | The domain should match the integration domain. |
INFO
Creating separate Business Rules for each operation allows us to pass the name of the operation to TransactionUtils.checkIntegrationTriggersAsync() when using async Business Rules. We have to do this because current.operation is not available in async Business Rules, and the operation is used to match the trigger of the Integration.
Async trigger
(function executeRule(current, previous /*null when async*/) {
const transactionUtils = x_devol_intgr_mgr.TransactionUtils;
const transactionManager = x_devol_intgr_mgr.TransactionManager;
transactionUtils
.checkIntegrationTriggersAsync(current, "update")
.integrationIds.forEach((id) => transactionManager.createTransaction(current, id, "update"));
})(current, previous);(function executeRule(current, previous /*null when async*/) {
const transactionUtils = x_devol_intgr_mgr.TransactionUtils;
const transactionManager = x_devol_intgr_mgr.TransactionManager;
transactionUtils
.checkIntegrationTriggersAsync(current, "update")
.integrationIds.forEach((id) => transactionManager.createTransaction(current, id, "update"));
})(current, previous);Synchronous trigger passing initial inputs
It is possible to run the trigger synchronously, but still have the Integration execute asynchronously. This is useful when you need to get access to the fields that changed on a record when an update happened.
In this example we generate a list of the updated fields synchronously, and pass that list to the Integration that will execute asynchronously. The list of updated fields will be available in the inputs of the first Step.
(function executeRule(current, previous /*null when async*/) {
const transactionUtils = x_devol_intgr_mgr.TransactionUtils;
const transactionManager = x_devol_intgr_mgr.TransactionManager;
const updatedFields = global.GlobalBridgeUtils.getUpdatedFields(current);
transactionUtils
.checkIntegrationTriggersAsync(current, "update")
.integrationIds.forEach((id) =>
transactionManager.createTransaction(current, id, "update", { updatedFields })
);
})(current, previous);(function executeRule(current, previous /*null when async*/) {
const transactionUtils = x_devol_intgr_mgr.TransactionUtils;
const transactionManager = x_devol_intgr_mgr.TransactionManager;
const updatedFields = global.GlobalBridgeUtils.getUpdatedFields(current);
transactionUtils
.checkIntegrationTriggersAsync(current, "update")
.integrationIds.forEach((id) =>
transactionManager.createTransaction(current, id, "update", { updatedFields })
);
})(current, previous);Synchronous Integrations
Integration Manager contains a utilty that can be used when an Integration needs to run synchronously.
A common use case for this would be a Scripted REST API that needs to send synchronous responses.
(function process( /*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
// create an inbound http request that will be used as the Integration's initRecord
var gr = new GlideRecord("x_devol_intgr_mgr_inbound_http_request");
gr.setValue("headers", JSON.stringify(request.headers));
gr.setValue("body", JSON.stringify(request.body.data));
gr.setValue("query", JSON.stringify(request.queryParams));
gr.setValue("uri", request.uri);
gr.setValue("url", request.url);
gr.setValue("method", "post");
gr.insert();
// define the configuration for the Integration
var integrationId = "integration_sys_id_goes_here"; // replace the placeholder with the integration's sys_id
var operation = "insert"; // which operation to pass to the integration
var initialInputs = {}; // this can be used to provide some initial data that will be available as inputs for the first step
// run the integration synchronously
var result = x_devol_intgr_mgr.TransactionManager.runIntegration(gr, integrationId, operation, initialInputs); // this will return the outputs of the last step in the integration
response.setStatus(201);
response.setBody(result);
})(request, response);(function process( /*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
// create an inbound http request that will be used as the Integration's initRecord
var gr = new GlideRecord("x_devol_intgr_mgr_inbound_http_request");
gr.setValue("headers", JSON.stringify(request.headers));
gr.setValue("body", JSON.stringify(request.body.data));
gr.setValue("query", JSON.stringify(request.queryParams));
gr.setValue("uri", request.uri);
gr.setValue("url", request.url);
gr.setValue("method", "post");
gr.insert();
// define the configuration for the Integration
var integrationId = "integration_sys_id_goes_here"; // replace the placeholder with the integration's sys_id
var operation = "insert"; // which operation to pass to the integration
var initialInputs = {}; // this can be used to provide some initial data that will be available as inputs for the first step
// run the integration synchronously
var result = x_devol_intgr_mgr.TransactionManager.runIntegration(gr, integrationId, operation, initialInputs); // this will return the outputs of the last step in the integration
response.setStatus(201);
response.setBody(result);
})(request, response);Configuration
The Run synchronously field on the Integration record should be set to true, this disqualifies the Integration from getting identified by Triggers. Instead, the runIntegration method in TransactionManager will be used to target and execute the Integration, as demonstrated in the example above.