API Script Guide
- Instana API script reference
- Writing a REST API test case
- Managing modules
- Testing and debugging API script locally
- Script examples
Instana API script reference
The Instana API script interacts with Instana API to perform operations that enhance the monitoring abilities of Instana. The API script supports Node.js 16.
Global variables
The Instana Synthetic API script uses the following predefined global variables to accelerate script development:
APIs | Details |
---|---|
$http |
Send HTTP request by request module (deprecated) |
$got |
Send HTTP request by got module |
$secure |
Access user credentials |
$attributes |
Manage customized attributes |
$network |
Set up proxy by using this network utility |
$synthetic |
Access environment and runtime variables |
$env |
Access environment variables |
$util |
Use utility functions, such as security APIs |
$http
One or more requests can be sent in a single API script. The Instana Synthetic API script uses the predefined variable $http
or $got
to send an HTTP request. The $http
variable is based on the request module that is deprecated now. This variable is temporarily reserved and later removed in the future.
For more information about how to use $http
, see API Script Guide.
$got
To avoid issues that might arise on removing $http
in the future, use the $got
variable to send an HTTP request from Synthetic PoP 1.0.13. This variable uses the got module.
For more information about how to send different types of HTTP requests with $got
, see Writing a REST API test case.
$secure
The Instana API script supports user credentials to store the secrets securely, such as password or authentication key.
To create a credential with the API, complete the following steps:
- Make sure that you have proper permission setting.
- Use Synthetic OpenAPI to create a credential by passing
credentialName
andcredentialValue
.
Then, in your API script, use $secure.credentialName
to refer to the created credential, for example, $secure.password
or $secure.API_KEY
.
$synthetic
You can use $synthetic.var_name
to access environment and runtime variables in the script. See the following predefined variables:
- $synthetic.LOCATION or $synthetic.pop: Used to access the location label, which is the first part in the controller.location variable.
- $synthetic.TEST_ID or $synthetic.id: Used to access the identifier of Synthetic test that is executed.
- $synthetic.TEST_NAME or $synthetic.testName: Used to access the test label of Synthetic test that is executed.
- $synthetic.TIME_ZONE or $synthetic.timeZone: Used to access the time zone of the PoP that runs the Synthetic test.
- $synthetic.JOB_ID or $synthetic.taskId: Used to access the identifier of playback task, and it is also the result ID.
- $synthetic.testType: Used to access the test type.
- $synthetic.description: Used to access the test description.
You can also define custom environment variables in values.yaml
of the helm chart. See the following example:
controller:
customProperties: "tag1=value1;tag2=value2"
Then, use $synthetic.tag1
and $synthetic.tag2
in the script to access these custom variables.
To access the custom properties that are defined in the customProperties section of the test definition, you can use $synthetic.labels.xxx
to access the property value in the script. See the following example:
// to print test custom tags/labels
console.log('Test Label $synthetic.labels.Team: ' + $synthetic.labels.Team);
console.log('Test Label $synthetic.labels.Purpose: ' + $synthetic.labels.Purpose);
$env
To access environment variables in the script, use $env.MY_ENV_VARIABLE
.
- $env.LOCATION: Used to access the location label, which is the first part in controller.location variable.
- $env.TEST_ID or $env.MONITOR_ID: Used to access the identifier of the Synthetic test.
- $env.TEST_NAME: Used to access the test label of the Synthetic test.
- $env.TIME_ZONE: Used to access time zone of the PoP running the Synthetic test.
- $env.JOB_ID: Used to access the identifier of playback task.
- $env.MONITOR_TYPE: Used to access the test type, which is the same as $synthetic.testType.
Note: The values of $env.LOCATION
, $env.TEST_ID
, $env.TEST_NAME
, $env.TIME_ZONE
, and $env.JOB_ID
are the same as variables in $synthetic
for compatibility.
The custom environment variables can be defined in the values.yaml file of helm chart, for example:
controller:
customProperties: "tag1=value1;tag2=value2"
Then, use $env.tag1
and $env.tag2
in the script to access these custom variables.
$attributes
Use $attributes
to add or get custom attributes to monitor data. API Script developers can add custom key/value
pair data as custom attributes. The custom data serves as an addition to the default attributes. These
custom attributes are also stored in the monitor results with other default monitor result attributes. To access the custom attributes, use $attributes
in the Instana API script:
$attributes.set('tag1', 'value1') // sets tag tag1 to value value1
let v = $attributes.get('tag1') // sets variable v to the value of tag1
$network
The following APIs are supported in Instana synthetic monitoring for configuring proxy server:
$network.setProxy(string proxy)
: Used to set a proxy server to be used for all requests (HTTP, HTTPS).$network.setProxyForHttp(string proxy)
: Used to set a proxy server to be used for only HTTP requests.$network.setProxyForHttps(string proxy)
: Used to set a proxy server to be used for only HTTPs requests.$network.clearProxy()
: Used to remove the proxy configuration.$network.getProxy()
: Used to return the proxy configuration.
The following example uses proxy:
const assert = require('assert');
// Proxy with ip:port
// $network.setProxy('http://proxyhost:port');
// $network.setProxyForHttp('http://proxyhost:port');
// $network.setProxyForHttps('http://proxyhost:port');
// Proxy with authentication, create proxyUser and proxyPass credentials first
$network.setProxy('http://' + $secure.proxyUser + ':' + $secure.proxyPass + '@proxyhost:port');
// retrieve proxy
// let proxy = $network.getProxy();
$util.secrets
Use this security API to redact sensitive data.
All known sensitive information is masked with the * character before the information is written into logging files and sent to backends.
Synthetic PoP does not collect HTTP header and body data. If you want to redact secrets from URLs, use the command $util.secrets.setURLSecretsRegExps in your script. See the following example:
// to redact 'key', 'password' and 'secret' query parameters in URL
$util.secrets.setURLSecretsRegExps([/key/i, /password/i, /secret/i]);
After this API is called, the URL https://example.com/accounts/status?key=mykey123&secret=mysecret
is collected and displayed as https://example.com/accounts/status?key=*&secret=*
in the Instana UI.
Writing a REST API test case
To write a REST API test case, complete the following steps:
-
Send an HTTP request. The following example shows how to send the HTTP GET and POST requests and validate their status code and response body:
const assert = require('assert'); (async function () { // GET example const {statusCode} = await $got.get('https://httpbin.org/get'); assert.equal(statusCode, 200, 'Expected a 200 Status Code, current is ' + statusCode); // POST example var postOptions = { url: 'https://httpbin.org/post', json: { 'name': 'TestName', 'type': 'Synthetic Script' }, https:{ rejectUnauthorized: false }, headers:{'accept': 'application/json'} }; let postResponse = await $got.post(postOptions); assert.ok(postResponse.statusCode == 200, 'POST status is ' + postResponse.statusCode + ', it should be 200'); const jsonBody = JSON.parse(postResponse.body); assert.equal(jsonBody.json.name, 'TestName', 'Expected TestName'); assert.equal(jsonBody.json.type, 'Synthetic Script', 'Expected Synthetic Script'); })();
By default, Got will retry 2 times on failure. To disable this option, set options.retry to
{limit: 0}
. -
To validate the results, import the
assert
module by using theconst assert=require('assert');
command and call theassert
method to validate the endpoint response.To validate response statusCode, see the following example:
const assert=require('assert'); assert.ok(response && response.statusCode == 200, 'Expected a 200 status code, statusCode is ' + response.statusCode); assert.equal(response.statusCode, 200, 'Expected a 200 status code')
To validate response content, see the following example:
let bodyObj = (typeof body == 'string') ? JSON.parse(body) : body; assert.ok(bodyObj.id != null, 'id should not be null');
For more assert APIs, see assert API. Another module to validate the result is chai.
-
To debug the script, use the
console
command. You can see the log contents in the Instana UI.console.info() console.log() console.error() console.warn()
Sending GET HTTP requests
To send a GET request, use the following syntax:
const assert = require('assert');
(async function () {
var options = {
url: 'https://reqres.in/api/messages',
https:{ rejectUnauthorized: false }
};
// Send GET request
let response = await $got.get(options);
// Validate the response status code, it should be 200 here
assert.ok(response && response.statusCode == 200, 'Expect 200');
})();
Sending POST HTTP requests
To send a POST JSON request, use the following syntax:
const assert = require('assert');
(async function () {
// Send JSON Data example
let URL = 'https://reqres.in/api/users';
// Define JSON data
let data = {
'job': 'leader',
'name': 'morpheus'
};
// Make POST request
let response = await $got.post(URL, {
header: {
'content-type': 'application/json'
},
json: data
});
// Validate the response code, if assertion fails, log "failed to create message, error is " plus
// results as error message on synthetic dashboard
assert.ok(response && response.statusCode == 201, 'expect 201');
})();
To send a POST form request, use the following syntax:
const assert = require('assert');
(async function () {
const response = await $got.post('https://httpbin.org/anything', {
form: {
text: 'hello world'
}
});
assert.ok(response && response.statusCode == 200, 'expect 200');
})();
Sending TLS/SSL support requests
To send an HTTPS request and allow insecure certificate, use the following syntax:
// Allow the insecure certificate
await $got('https://example.com', {
https:{ rejectUnauthorized: false }
});
To send a TLS/SSL Protocol request with a certificate, use the following syntax:
// Single key with passphrase
await $got('https://example.com', {
https: {
key: $secure.key,
certificate: $secure.certificate,
passphrase: $secure.passphrase
}
});
Note: Create credentials to store key, certificate, and passphrase.
Sending basic authentication requests
To send a basic authentication request, use the following syntax:
await $got.get('http://some.server.com/', {
https:{ rejectUnauthorized: false },
headers: {
Authorization: "Basic " + $secure.AUTH_CRED
}
});
Note: You need to create a credential variable AUTH_CRED
to store the username and password of HTTP Basic authentication.
The format of the AUTH_CRED
credential variable is username:password
that is encoded with base64
.
Sending requests with a bear token
To send a bear authentication request, use the following syntax:
await $got.get('http://some.server.com/', {
headers: {
'Authorization': "Bearer " + $secure.authToken
}
});
Note: Create credential to store the bear authToken text.
Managing modules
Importing optional module
To import a supported module, follow the standard procedure about Node.js importing. See the following example:
const crypto = require('crypto-js');
Supported core modules
The supported core modules are as follows:
- assert
- async_hooks
- buffer
- constants
- crypto
- dgram
- dns
- domain
- events
- fs
- http
- http2
- https
- module
- net
- os
- path
- perf_hooks
- punycode
- querystring
- stream
- string_decoder
- timers
- tls
- trace_events
- tty
- url
- util
- zlib
Supported third-party modules
The following third-party modules are supported:
- assert-plus 1.0.0
- atob 2.1.2
- @aws-sdk/client-s3 3.348.0
- @babel/core 7.18.5
- basic-ftp 4.6.6
- body-parser 1.20.0
- btoa 1.2.1
- clone 0.1.19
- colors 1.4.0
- consoleplusplus 1.4.4
- crypto-js 4.1.1
- debug 2.6.9
- extend 3.0.2
- faker 5.5.3
- got 11.8.6
- joi 17.6.0
- js-yaml 3.14.1
- jsprim 1.4.2
- kafkajs 2.2.4
- ldapauth-fork 5.0.5
- lodash 4.17.21
- moment 2.29.4
- net-snmp 3.8.2
- node-stream-zip 1.15.0
- protocol-buffers 4.2.0
- q 1.5.1
- request 2.88.2
- should 13.2.3
- ssh2-sftp-client 7.2.3
- sshpk 1.17.0
- ssl-checker 2.0.8
- swagger-parser 8.0.4
- text-encoding 0.7.0
- thrift 0.14.2
- tough-cookie 4.1.3
- underscore 1.13.4
- unzipper 0.10.11
- url-parse 1.5.10
- urllib 2.38.0
- uuid 3.4.0
- validator 13.7.0
- ws 7.5.8
- xml2js 0.5.0
Testing and debugging API script locally
synthetic-api-script
is a node module to develop and debug API script in local environment. For more information, see the readme file.
Using the script-cli command
To test and debug API script, use the script-cli
command as shown in the following example:
# Usage:
# test a single script
script-cli <script_name>
# test bundled scripts
script-cli -d <dir> <script-entry-file>
# Example:
script-cli examples/example1.js
script-cli -d examples/bundle-example1 index.js
Creating a single API script test
After you create a Synthetic script, complete the following steps:
-
Use
synthetic-api-script
to create an API script, and convert the script to string with thescript-cli
command:# Usage: script-cli -s <script-file-path> # Example: script-cli -s examples/got-get.js
The following example displays the result:
{ "syntheticType":"HTTPScript", "script":"var assert = require('assert');\n\n(async function() {\n var options = {\n url: 'https://httpbin.org/get',\n https:{\n rejectUnauthorized: false\n }\n };\n\n let response = await $got.get(options);\n assert.equal(response.statusCode, 200, 'Expected a 200 OK response');\n console.log('Request URL %s, statusCode: %d', response.url, response.statusCode);\n})();\n" }
-
Copy and paste the script content to build the following example API script test JSON.
{ "label": "APIScript_Test", "active": true, "testFrequency": 1, "locations": ["DemoPoP1_saas_instana_test"], "configuration": { "syntheticType": "HTTPScript", "script": "converted script string" } }
Creating a bundled API script test
If the business logic is complex, do not contain everything in a single script because it's difficult for developers to manage multiple script files in a Git repository.
To create a bundled API script test, complete the following steps:
-
Bundle scripts in a compressed file by using the script-cli command:
# Usage: script-cli -z <bundle-script-folder> <entry-script> # Example: script-cli -z bundle-example1 bundle-example1/index.js
-
Fill
scriptFile
andbundle
in the test configuration with the output of thescript-cli
command:scriptFile
is the entry point of the bundled scripts.bundle
is the compressed file encoded with base64.
To create Synthetic bundled test, fill test payload as shown in the following example:
{
"label": "APIScriptBundle_Test",
"active": true,
"testFrequency": 5,
"locations": ["DemoPoP1_saas_instana_test"],
"configuration": {
"syntheticType": "HTTPScript",
"scripts": {
"scriptFile": "index.js",
"bundle": "zipped scripts encoded with base64"
}
}
}
Script examples
Example 1: Instana API script to test httpbin APIs
You can use the Instana API script to test the httpbin APIs in a synchronized way as follows:
const assert = require('assert');
(async function () {
var getOptions = {
url: 'https://httpbin.org/get',
https:{ rejectUnauthorized: false },
headers: {
'Additional-Header': 'Additional-Header-Data'
}
};
let getResponse = await $got.get(getOptions);
console.info("Sample API - GET, response code: " + getResponse.statusCode);
assert.ok(getResponse.statusCode == 200, "GET status is " + getResponse.statusCode + ", it should be 200");
var bodyObj1 = JSON.parse(getResponse.body);
assert.ok(bodyObj1.url == "https://httpbin.org/get", "httpbin.org REST API GET URL verify failed");
var postOptions = {
url: 'https://httpbin.org/post',
json: {
"name1": "this is the first data",
"name2": "second data"
},
https:{ rejectUnauthorized: false },
headers:{"accept": "application/json"}
};
let postResponse = await $got.post(postOptions);
console.info("Sample API - POST, response code: " + postResponse.statusCode);
assert.ok(postResponse.statusCode == 200, 'POST status is ' + postResponse.statusCode + ', it should be 200');
const jsonBody2 = JSON.parse(postResponse.body);
assert.equal(jsonBody2.json.name1, 'this is the first data', 'Expected this is the first data');
assert.equal(jsonBody2.json.name2, 'second data', 'Expected second data');
var putOptions = {
url: 'https://httpbin.org/put',
json: {
"name1": 'this is the first data',
"name2": 'second data'
},
https:{ rejectUnauthorized: false },
headers:{"accept": "application/json"}
};
let putResponse = await $got.put(putOptions);
console.info("Sample API - PUT, response code: " + putResponse.statusCode);
assert.ok(putResponse.statusCode == 200, 'PUT status is ' + putResponse.statusCode + ', it should be 200');
const jsonBody3 = JSON.parse(putResponse.body);
assert.ok(jsonBody3.url == "https://httpbin.org/put", "httpbin.org REST API PUT URL verify failed");
assert.equal(jsonBody3.json.name2, 'second data', 'Expected second data');
var deleteOptions = {
url: 'https://httpbin.org/delete',
https:{ rejectUnauthorized: false },
headers:{"accept": "application/json"}
};
let deleteResponse = await $got.delete(deleteOptions);
console.info("Sample API - DELETE, response code: " + deleteResponse.statusCode);
assert.ok(deleteResponse.statusCode == 200, 'DELETE status is ' + deleteResponse.statusCode + ', it should be 200');
const jsonBody4 = JSON.parse(deleteResponse.body);
assert.ok(jsonBody4.url == "https://httpbin.org/delete", "httpbin.org REST API DELETE URL verify failed");
// to print environment variables
console.info('List PoP environment variables using $synthetic API');
console.info('Test ID:', $synthetic.TEST_ID);
console.info('Test Name:', $synthetic.TEST_NAME);
console.info('Location:', $synthetic.LOCATION);
console.info('TimeZone:', $synthetic.TIME_ZONE);
console.info('Job ID:', $synthetic.JOB_ID);
// to print test custom tags/labels
console.info('Test Label $synthetic.labels.Team: ' + $synthetic.labels.Team);
console.info('Test Label $synthetic.labels.Purpose: ' + $synthetic.labels.Purpose);
// to set custom tags dynamically
$attributes.set('custom_tag1', 'value1');
})();
Example 2: Instana API script to test website certificate
You can use the Instana API script to test the SSL certificate for ibm.com as follows:
const sslChecker = require('ssl-checker');
const assert = require('assert');
const hostname = 'ibm.com';
const remainDays = 90;
const getSslDetails = async(hostname) => {
const result = await sslChecker(hostname);
console.log(`certificate is valid: ${result.valid}`);
console.log(`certificate expires on: ${result.validTo}`);
console.log(`certificate days remaining: ${result.daysRemaining}`);
assert.equal(result.valid, true, 'certificate of ibm should be valid');
// this script will fail if the certificate remaining days less than 90 days by default
// modify variable remainDays to any value as you need
assert.equal(result.daysRemaining >= remainDays, true, `certificate validated remain days is less than ${remainDays} days`);
};
getSslDetails(hostname);
For more API script examples, see synthetic API script.