Customization examples

This page provides detailed examples of the most common adapter customizations. Each section shows how to customize different aspects of your adapter’s behavior.

Dynamic input

You can change any information on the request in adapter.js when setting the request object.

Information can be placed into adapter.js if it applies to a specific action. Dynamic information can come from Itential Platform if it is in the method signature of the adapter method.

Example: A dynamic input within the request object

1someCall(id, body, auditValue, callback) {
2 /* HERE IS WHERE YOU SET THE DATA TO PASS INTO REQUEST */
3 let callHeaders = { hdr1: auditValue };
4
5 // set up the request object - payload, uriPathVars, uriQuery, uriOptions,
6 // addlHeaders, authData, callProperties, filter, priority and event
7 const reqObj = {
8 payload: body,
9 uriPathVars: [id],
10 uriOptions: { page: 1 },
11 authData: callHeaders
12 };
13}

In this example, the auditValue parameter is passed into the method and used to set authentication headers dynamically. This allows callers to provide different audit values for different requests.

Customizing the response

You can change any information in the response within adapter.js prior to sending it back to Itential Platform. This includes:

  • Handling embedded errors that may not be detected by the generic adapter libraries
  • Performing calculations on the data that is returned and adding the results into the response
  • There is no need to do translations here if schemas are set up properly, but you can if it is desired

Example: Customizing the response

1// Make the call -
2// identifyRequest(entity, action, requestObj, returnDataFlag, callback)
3return this.requestHandlerInst.identifyRequest('entity', 'action', reqObj, true,
4 (irReturnData, irReturnError) => {
5 // if we received an error or there is no response on the results
6 // return an error
7 if (irReturnError) {
8 /* HERE IS WHERE YOU CAN ALTER THE ERROR MESSAGE */
9 return callback(null, irReturnError);
10 }
11 if (!Object.hasOwnProperty.call(irReturnData, 'response')) {
12 const errorObj = this.requestHandlerInst.formatErrorObject(
13 this.id,
14 meth,
15 'Invalid Response',
16 ['action'],
17 null,
18 null,
19 null
20 );
21 log.error(`${origin}: ${errorObj.IAPerror.displayString}`);
22 return callback(null, errorObj);
23 }
24
25 /* HERE IS WHERE YOU CAN ALTER THE RETURN DATA */
26 // return the response
27 const newObj = {
28 number: irReturnData.response.length,
29 data: irReturnData.response
30 };
31 return callback(newObj, null);
32 }
33);

In this example, the response is modified to include a count of items and wrap the original data in a new structure.

Request payload

Payload is simply the body that is sent out on the request to the other system.

If the payload is JSON, it will be translated based on the schema for the particular action. The reason it is translated is when Itential Platform refers to a field as X and the other system refers to it as Y, the adapter needs to put the value in X into Y before calling the other system so that the other system will understand the request.

The payload can also be plain text or XML in which case nothing will be done with it. Other actions can be done based on the requestDatatype defined in the action.json file. These include encoding, encrypting, URL handling as a form, and translating from JSON to XML.

Example: A request payload

1const reqObj = {
2 payload: { garbage: 'need since post' },
3 uriPathVars: [groupId, deviceId],
4 uriQuery: { name: 'anyname' },
5 uriOptions: { page: 2 },
6 addlHeaders: { audit: 'turnOn' },
7 authData: { domain: 'abc' },
8 callProperties: {
9 stub: true,
10 request: {
11 attempt_timeout: 60000
12 }
13 },
14 filter: '[*name=doggie]',
15 priority: 1,
16 event: 'giveMeMyData'
17};

This example shows a complete request object with a payload and various other parameters. The payload will be translated according to the schema before being sent to the external system.

Request path

Path variables are used to dynamically set data in the call path to the other system.

When the call path is defined (see path example below), the path variables will be used to replace {pathv1} and {pathv2} in the call path:

  • uriPathVars is an array
  • uriPathVars[0] will be used to replace {pathv1} and uriPathVars[1] will be used to replace {pathv2}

Example: Request path variables

1const reqObj = {
2 payload: { garbage: 'need since post' },
3 uriPathVars: [groupId, deviceId],
4 uriQuery: { name: 'anyname' },
5 uriOptions: { page: 2 },
6 addlHeaders: { audit: 'turnOn' },
7 authData: { domain: 'abc' },
8 callProperties: {
9 stub: true,
10 request: {
11 attempt_timeout: 60000
12 }
13 },
14 filter: '[*name=doggie]',
15 priority: 1,
16 event: 'giveMeMyData'
17};

Path transformation:

api/v1/devices/{pathv1}/interface/{pathv2}?{query}

Replaced with:

api/v1/devices/dev123/interface/int123?{query}

Request query parameters

Query parameters are translated based on the defined schema for the particular action. The reason they are translated is when Itential Platform refers to a field as X and the other system refers to it as Y, the adapter needs to put the value in X into Y before putting it into the query parameters for the call to the other system. This will allow the other system to understand the request.

The query object is then converted to a querystring by the Adapter libraries and appended to the call.

Example: Request query parameters

1const reqObj = {
2 payload: { garbage: 'need since post' },
3 uriPathVars: [groupId, deviceId],
4 uriQuery: { name: 'anyname' },
5 uriOptions: { page: 2 },
6 addlHeaders: { audit: 'turnOn' },
7 authData: { domain: 'abc' },
8 callProperties: {
9 stub: true,
10 request: {
11 attempt_timeout: 60000
12 }
13 },
14 filter: '[*name=doggie]',
15 priority: 1,
16 event: 'giveMeMyData'
17};

Path transformation:

/api/v1/devices/{pathv1}/interface/{pathv2}?{query}

Replaced with:

/api/v1/devices/grp123/interface/dev123?name=anyname

Request options

Call options are query parameters that are not translated. These are generally metadata on the request. Some examples include page or page_size.

The call option object is converted to a querystring by the Adapter libraries and appended to the call.

Example: Request options

1const reqObj = {
2 payload: { garbage: 'need since post' },
3 uriPathVars: [groupId, deviceId],
4 uriQuery: { name: 'anyname' },
5 uriOptions: { page: 2 },
6 addlHeaders: { audit: 'turnOn' },
7 authData: { domain: 'abc' },
8 callProperties: {
9 stub: true,
10 request: {
11 attempt_timeout: 60000
12 }
13 },
14 filter: '[*name=doggie]',
15 priority: 1,
16 event: 'giveMeMyData'
17};

Path transformation:

/api/v1/devices/{pathv1}/interface/{pathv2}?{query}

Replaced with:

/api/v1/devices/grp123/interface/dev123?name=anyname&page=2

Note how both query parameters (translated) and options (not translated) are combined in the final URL.

Dynamic headers

In some cases, dynamic headers should be added to a call. This can include changing the content-type, providing audit headers, or supplying other headers needed on the request.

Dynamic headers can be encoded in the adapter.js, or you can pass them into adapter.js and then add a method param. If headers are the same on every call and static, consider using a global_request property to define the headers instead of adding them into every method in the adapter.js.

Example: Dynamic headers

1const reqObj = {
2 payload: { garbage: 'need since post' },
3 uriPathVars: [groupId, deviceId],
4 uriQuery: { name: 'anyname' },
5 uriOptions: { page: 2 },
6 addlHeaders: { audit: 'turnOn' },
7 authData: { domain: 'abc' },
8 callProperties: {
9 stub: true,
10 request: {
11 attempt_timeout: 60000
12 }
13 },
14 filter: '[*name=doggie]',
15 priority: 1,
16 event: 'giveMeMyData'
17};

In this example, the addlHeaders property adds an audit header to the request. These headers are included with every request made with this request object.

Dynamic authentication

In some cases, dynamic authentication is needed based on a certain set of criteria (for example, domains).

Use authData to feed this information into the Adapter Utils so that a request can be dynamically authenticated based on the criteria that was set. When the authData param is added to adapter.js, it is added to the Authentication request object.

Example: Dynamic authentication data

1const reqObj = {
2 payload: { garbage: 'need since post' },
3 uriPathVars: [groupId, deviceId],
4 uriQuery: { name: 'anyname' },
5 uriOptions: { page: 2 },
6 addlHeaders: { audit: 'turnOn' },
7 authData: { domain: 'abc' },
8 callProperties: {
9 stub: true,
10 request: {
11 attempt_timeout: 60000
12 }
13 },
14 filter: '[*name=doggie]',
15 priority: 1,
16 event: 'giveMeMyData'
17};

In this example, the authData property provides domain information that can be used by the authentication handler to authenticate differently based on the domain.

Individual call properties

As shown previously, you can override adapter properties on an individual request. You only need to get the info into the adapter by exposing parameters in the adapter.js method.

Most properties can be changed on a request. Exceptions to this include throttling (do not bypass or change the queue handling) and healthcheck.

Example: Individual call properties

1const reqObj = {
2 payload: { garbage: 'need since post' },
3 uriPathVars: [groupId, deviceId],
4 uriQuery: { name: 'anyname' },
5 uriOptions: { page: 2 },
6 addlHeaders: { audit: 'turnOn' },
7 authData: { domain: 'abc' },
8 callProperties: {
9 stub: true,
10 request: {
11 attempt_timeout: 60000
12 }
13 },
14 filter: '[*name=doggie]',
15 priority: 1,
16 event: 'giveMeMyData'
17};

In this example, callProperties overrides the adapter configuration to enable stub mode and set a custom timeout for this specific request.

Filtering the response

Not all systems provide filtering capabilities.

The adapter will filter the response data based on dynamic criteria provided in the request. The filter string is a JSON Query used to filter the incoming data. Since the filter is in the request object it can be set up on a request-by-request basis.

This param is used to request that a system return all the devices that start with “ABC”.

Example: Filtering a response

1const reqObj = {
2 payload: { garbage: 'need since post' },
3 uriPathVars: [groupId, deviceId],
4 uriQuery: { name: 'anyname' },
5 uriOptions: { page: 2 },
6 addlHeaders: { audit: 'turnOn' },
7 authData: { domain: 'abc' },
8 callProperties: {
9 stub: true,
10 request: {
11 attempt_timeout: 60000
12 }
13 },
14 filter: '[*name=abc]',
15 priority: 1,
16 event: 'giveMeMyData'
17};

The filter string [*name=abc] tells Adapter Utils to filter the response and only return items where the name field starts with “abc”.

Priorities and events

Priority and event are both specific to throttling.

Priority

Priority is a way to prioritize items in the throttle queue.

The priority must correspond to the value defined in the priorities array in the adapter properties. The adapter will queue the request based on the percent value for the matching priority. Zero percent (0%) indicates the request is at the front of the queue and 100% means it is at the end of the queue.

Event

Event tells the adapter how to return the result when the caller has decided not to wait for the response.

The adapter will trigger the event when the response is ready so that the caller can then know the result is ready.

Example: Priority and event

1const reqObj = {
2 payload: { garbage: 'need since post' },
3 uriPathVars: [groupId, deviceId],
4 uriQuery: { name: 'anyname' },
5 uriOptions: { page: 2 },
6 addlHeaders: { audit: 'turnOn' },
7 authData: { domain: 'abc' },
8 callProperties: {
9 stub: true,
10 request: {
11 attempt_timeout: 60000
12 }
13 },
14 filter: '[*name=abc]',
15 priority: 1,
16 event: 'giveMeMyData'
17};

In this example, the request is assigned priority 1 (which must match a configured priority in the adapter properties), and the event giveMeMyData will be triggered when the response is ready.

What’s next