API for connectors

<< Click to Display Table of Contents >>

Navigation:  Bizagi Studio > Integrating external applications from Bizagi > Bizagi connectors > Creating connectors > Custom connectors >

API for connectors

Overview

When creating your own Bizagi connectors, and specifically a custom connector, you will need to write your own code, as described at Custom connectors.

In order to do this, it is important that you rely on the API provided by Bizagi when applicable.

 

Starting point and API objects

The starting point when creating your custom Bizagi connector is implementing the invoke function as included by Bizagi when defining a new action:

 

Invokefn

 

note_pin

Note you may include additional functions to help you out organize your code. However, what you need to acknowledge is that the invoke function will always be the starting point when Bizagi runs a connector's given action.

 

In this function you may include code as supported by JavaScript and as provided by Bizagi API.

Within the function's input parameters, notice you are provided with the following objects:

 

OBJECT

TYPE

DESCRIPTION AND EXAMPLE

globals

Object

Contains all parameters as defined within the tabs presented in the rightmost panel: Connector, Authentication and Errors.

These parameters are accessed according to the above categories, as:

Connector parameters: globals.systemproperties.[your_parameter]

Authentication parameters: globals.authdata.[your_parameter]

 

For more information about the global parameters, click here.

Additionally, the project's name is available as globals.projectname

actionName

String

Contains the name of the action you are implementing.

Though it is not commonly needed, the purpose of this information is for you to use for detailed tracing and logging.

data

Object

Contains all values that make part of the defined inputs and the defined outputs.

Access them as:

data.inputs.input.[structure_inside_input] (as defined in your input structure)

data.outputs.output.[structure_inside_output] (as defined in your output structure) or data.outputs.error.[structure_inside_error]

authenticationType

Object

Contains the authentication types supported by your implementation. Though it is not commonly needed, the purpose of this object is for you to check its value to separate the implementation of your action should you need to use more than 1 type of authentication (basic, digest or oauth2).

None can be also valid.

LOG

Object

Enables the use of the tracing.

It provides a set of functions for you to write into the logged detail in different tracing levels (debug, info, error, warn or trace). For example:

LOG.info('detailed_stack');

callback

Function

Refers to the callback function you need to include to notify Bizagi that your invocation has been completed.

It receives mandatory JSON-structured information and its use is typically set as either:

callback(response_information); for a successful invocation

callback(error); should an error occur

 

For further information about the callback function, click here.

 

API (bz-util)

The API for you to use in custom connectors is provided by the bz-util library which is automatically included in every new connector (these part from already having bizagiUtil as: var bizagiUtil = require ('bz-util'); ).

Methods offered by this API are described in the tables shown below.

 

METHOD AND INPUTS

OUTPUT AND DESCRIPTION

EXAMPLE

REQUIRED (string moduleName)

Imports a node.js library (specified by moduleName).

Returns an instance of the object of that imported library.

The following example, imports a node.js library called twit, into a variable set as TwitterService for further use:

 

var TwitterService = bizagiUtil.REQUIRED('twit');

getResponse (JSON response, JSON error, integer statuscode, string errormsg)

Allows you to format a successful response to send it back to Bizagi.

The successful response is to be set in the response JSON-structured parameter, while exceptions require filling in the JSON-structured parameter called error and a legible string-type error message (given by errormsg).

For either successful invocations or those presenting errors, it is recommended to define your own unique status codes (given by statuscode).

This example considers a successful invocation:

var success = bizagiUtil.getResponse({data: {key: ‘s22ssoj44sfj’}}, null, 200, null);

 

This example considers an error during the invocation:

var error = bizagiUtil.getResponse (null, {error: ‘invalid_request’}, 400, ‘The request is missing a required authentication parameter’);

validator.isValidDataJson (JSON json)

Validates if a JSON is well formed, i.e compliant to standard JSON for the data parameter.

Returns an object having a success element set to true if it is, while returns false if it doesn't, and it also pushes the JSON output or error structure accordingly into data.outputs.output or data.outputs.error.

 

The exact structure of the returned object is:

{

   response: {

       outputs: {

           output: {},

           error: {}

       }

   },

   success: true|false,

   connectorstatuscode: 200|?,

   errormessage: ""

}

This example validates the content in globals:

var result = bizagiUtil.validator.isValidDataJson(data);

if (result.success) {
   data = result.response.outputs.output;
} else´{
   callback(result);

return;
}  

validator.isValidGlobalsJson (JSON globals)

Validates if a JSON is well formed, i.e compliant to standard JSON, for the globals parameter.

Returns an object having a success element set to true if it is, while returns false if it doesn't, and it also pushes the JSON output or error structure accordingly into response.outputs.error.

 

The exact structure of the returned object is:

{

   response: {

       outputs: {

           output: { globals {...} },

           error: {}

       }

   },

   success: true|false,

   connectorstatuscode: 200|?,

   errormessage: ""

}

This example validates the content in globals:

var result = bizagiUtil.validator.isValidGlobalsJson(globals);

if (result.success) {
   globals = result.response.outputs.output;
} else´{
   callback(result);

return;
}  

error (string errorId, object[] detail)

Allows you to format an error so that you catch and manage it.

Error information gets structured with a main error identifier (errorId) and having further detail such as error code and detailed message.

This example formats an error message with a status-code 500:

 

var errormsg = bizagiUtil.error('OBJECT_REF', [500, 'Unsupported parameter value or unknown data']);

LOG.error (object[] detail)

Logs the detail provided in the message for error-level tracing. Notice you may concatenate into an array multiple texts.

The following 2 examples are valid:

LOG.error (['Error 009']);

LOG.error ('[My connector] Error:', error, {'invalid request'} ]);

LOG.debug (object[] detail)

Logs the detail provided in the message for debug-level tracing. Notice you may concatenate into an array multiple texts.

Same use as in LOG.error()

LOG. warn (object[] detail)

Logs the detail provided in the message for warning-level tracing. Notice you may concatenate into an array multiple texts.

Same use as in LOG.error()

LOG. trace (object[] detail)

Logs the detail provided in the message for basic tracing. Notice you may concatenate into an array multiple texts.

Same use as in LOG.error()

LOG.info (string[] message)

Logs the detail provided in the message for information-level tracing. Notice you may concatenate into an array multiple texts.

Same use as in LOG.error()

 

note_pin

Always use those traces and log capabilities offered by Bizagi API, which can be turned off and on by means of settings in Bizagi.

Make sure that you define accurately such information (the right amount of tracing, useful and legible information at best, etc), and do not log details into another destination.

 

Callback function

The callback function is in charge of notifying Bizagi when the invocation of an action has finished. Since the communication between the connector framework and the connector itself is asynchronous, this function is used as a communication bridge when the action ends its execution.

 

The callback function receives as a parameter a response type object, which has the following parameters:

output: JSON object with the same structure defined in the action's outputs. You have to include this parameter only for successful responses; else, its value is null.

errorOutput: JSON object with the same structure defined in the action's outputs. You have to include this parameter only for non successful responses, else, its value is null.

statusCode: code that indicates the status of the response. We recommend that you use the following status code nomenclature for when you code your actions:

oStatus codes from 400 to 500: To declare issues during authentication.

oNegative status codes: To declare exceptions in the logic of your invocation.

o200 status code: Should be specified for a successful invocation.

errorTitle: message shown when an error occurs. You may use the same value as the one specified in the errorOutput.error. You have to include this parameter only for non successful responses.

 

Using the Response object in the callback function

The following code illustrates an example of how to call the callback function when having a successful response:

 

var output = {
 id: 1,
 name: "First name"
}
var success = RESPONSE(output, null, 200);
callback(success);

 

In this case, the output, errorOutput and statusCode parameters are included in the response.

If an error occurs in the execution of the action, the callback function with the error response is defined as follows:

 

var errorOutput = {
 error: "Not Found",
 message: "The specified user does not exist."
 status: 404
}
var error = RESPONSE(null, errorOutput, 404, errorOutput.error);
callback(error);

 

In this case, the output, errorOutput, statusCode and errorTitle parameters are included in the response.

 

Take into account that the callback function does not end the execution of the action, hence, it must be called at the end of the action.

 

Correct implementation

Incorrect implementation

if (response.success) {
 var output = {
   id: 1,
   name: "First name"
 }
 var success = RESPONSE(output, null, 200);
 callback(success);
}

else {
 var errorOutput = {
   error: "Not Found",
   message: "The specified user does not exist."
   status: 404
 }
 var error = RESPONSE(null, errorOutput, 404, errorOutput.error);
 callback(error);
}

 

In this scenario, the callback is being called once. If the response is successful, or if there is an error.

if (response.success) {
 var output = {
   id: 1,
   name: "First name"
 }
 var success = RESPONSE(output, null, 200);
 callback(success);
}
var errorOutput = {
 error: "Not Found",
 message: "The specified user does not exist."
 status: 404
}
var error = RESPONSE(null, errorOutput, 404, errorOutput.error);
callback(error);

 

 

In this case, the callback function is being called twice. Instead, use an if-else structure to evaluate if the response is successful or not:

 

Error handling

When defining actions in a connector, it is important to detect and handle correctly the errors that may occur. The following sections illustrate some scenarios to handle errors successfully.

 

Required inputs

When an input is marked as required, you can verify that it is actually sent        . To do so, bz-util offers the validator module, which receives a JSON with the required parameters and validates that they are actually sent within the inputs. In case the validator finds an empty, undefined or null input, it generates a response object with the missing inputs that need to be sent.

 

The following code illustrates how to define the validator object and how to use it when calling an action.

 

Validator definition:

 

{
 "parameterName1": "path to parameter in data, ex: data.inputs.input.parameterName1",
 "parameterName2": "path to parameter in data, ex: data.inputs.input.parameterName2"
}

 

Using the validator in an action:

 

var bizagiUtil = require('bz-util');
var error = bizagiUtil.validator.requiredParameters({
 fileId: data.inputs.input.fileId,
 destinationPath: data.inputs.input.destinationPath
});
if(error){
 LOG.error(['[BOX.'+actionName+']', 'Error:', error]);
 return callback(error);
}

 

Error handling with Promises

A Promise is an object that represents the completion of an asynchronous operation, which could end successfully or with an error. Handling errors within Promises is quite simple; however, bear in mind that a classic try-catch structure will not work.

To handle errors regarding Promises, you have two options:

 

1.Use directly the catch function provided by the Promise itself:

 

axios.get(url)
   .then((response) => { /* code here */ })
   .catch((error) => { /* some error handling */ });

 

2.implement a try-catch structure using the await function:

 

try {
 let response = await axios.get(url);
} catch (error) {
 // some error handling
}

 

For further information about handling errors in Promises, click here.