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 18.
Global variables
The Instana Synthetic API script uses the following predefined global variables to accelerate script development:
APIs | Details |
---|---|
$got |
Send HTTP request by got module |
$http |
Send HTTP request by request module (deprecated) |
$secure |
Access user credentials |
$attributes |
Manage customized attributes |
$network |
Set up proxy by using this network utility |
$synthetic |
Access environment variables |
$util |
Use utility functions, such as security APIs |
$got
To replace $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.
$http (deprecated)
$http
is deprecated. Use $got
instead.
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 @cypress/request module. $http
is deprecated and temporarily reserved to be compatible with the old script and will later be removed in the future. Use the new variable $got
.
$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 or the synctl command 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
.
Only the $secure.credentialName
format is supported. The $secure[credentialName]
format is not supported.
$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 property defined in customProperties of test definition
console.info('Test custom property -> Team: ' + $synthetic.labels.Team);
console.info('Test custom property -> Purpose: ' + $synthetic.labels.Purpose);
$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 included in the test results along with the default attributes.
Instana Synthetic monitoring supports the following APIs for configuring custom attributes:
$attributes.set(key, value)
: Sets the key or value.$attributes.get(key)
: Returns the value for provided key.$attributes.getKeys()
: Returns an array of all keys.$attributes.has(key)
: Returnstrue
if the key exists.$attributes.unset(key)
: Removes the specified key.$attributes.unsetAll()
: Removes all the custom data.
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
The custom attributes set by $attributes
API in the script and custom properties defined by customProperties
section of the test definition can be accessed in the test results by synthetic.tags
metric,
you can use synthetic.tags
metric to filter the test results or pass custom value to Smart Alert custom payload.
$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
}
});
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
}
});
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 bearer token
To send a bearer authentication request, use the following syntax:
await $got.get('http://some.server.com/', {
headers: {
'Authorization': "Bearer " + $secure.authToken
}
});
Create credential to store the bearer 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-cloudwatch 3.624.0
- @aws-sdk/client-s3 3.626.0
- @aws-sdk/client-secrets-manager 3.624.0
- @aws-sdk/client-sts 3.624.0
- @babel/core 7.23.2
- akamai-edgegrid 3.4.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.2.0
- 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
- mongodb 6.5.0
- mssql 11.0.1
- net-snmp 3.8.2
- node-stream-zip 1.15.0
- prom-client 14.2.0
- protocol-buffers 4.2.0
- q 1.5.1
- request (based on @cypress/request@3.0.1)
- should 13.2.3
- sip 0.0.6
- ssh2-sftp-client 7.2.3
- sshpk 1.17.0
- ssl-checker 2.0.8
- swagger-parser 8.0.4
- telnet-client 2.2.1
- 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.43.0
- uuid 3.4.0
- validator 13.7.0
- ws 7.5.10
- xml2js 0.5.0
You cannot use require('@cypress/request')
directly to import a request module. Use require('request')
to import a request module or use the variable $http
.
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
Send API with credentials
To create credentials, you can use the synctl command. Creating a credential for the username and a credential for the password is shown in the following example:
synctl create cred --key username --value user123
synctl create cred --key password --value pass123
Basic authentication with the credentials is shown in the following example:
const assert = require('assert');
(async function(){
const auth = Buffer.from($secure.username + ":" + $secure.password).toString('base64');
let gotResponse = await $got.get('https://<your-basic-auth-url>', {
// If rejectUnauthorized is true, it will throw on invalid certificates, such as expired or self-signed ones.
https:{ rejectUnauthorized: false },
// set additional headers
headers: {
Authorization: `Basic ${auth}`
},
timeout: {
request: 10000 //ms
}
}
);
console.log('Response statusCode:', gotResponse.statusCode);
// verify status code
assert.ok(gotResponse.statusCode == 200, "GET statusCode is " + gotResponse.statusCode + ", it should be 200");
})();
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 getExample(){
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");
}
async function postExample(){
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');
}
async function putExample(){
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');
}
async function deleteExample(){
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");
}
function showEnvironment(){
// 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 property defined in customProperties of test definition
console.info('Test custom property -> Team: ' + $synthetic.labels.Team);
console.info('Test custom property -> Purpose: ' + $synthetic.labels.Purpose);
// to set custom tags dynamically
// Users can use tag key to to pass the customized value to Smart Alert custom payload
$attributes.set('tag_key1', 'value1');
}
async function main(){
await getExample();
await postExample()
await putExample();
await deleteExample();
await showEnvironment();
}
main();
For more API script examples, see Synthetic API script.