Configuring and Using Scripting

Overview

definition

Scripting makes it possible to extend API Simulator with functionality that’s not yet built-in.

Scripting vs. Scriptlets

Scripts can be used in matchers, parameters, and placeholders definitions. Such scripts get access to the execution context (the _context variable), and through that, to any parameter. Scripts can call functions defined in external libraries or can themselves define custom functions and methods. Out-of-the-box there is support for the JavaScript and Groovy scripting languages. Historically, scripts have been a feature of API Simulator pretty much since the beginning.

Java 15 removed the built-in JavaScript engine (nashorn). To use JavaScript scripts when running API Simulator with Java 15+, you’d have to add a few JARs for the nashorn JavaScript engine to the /path/to/apisimulator-installation/lib directory. For example:

  • nashorn-core-15.4.jar

  • asm-7.3.1.jar

  • asm-analysis-7.3.1.jar

  • asm-commons-7.3.1.jar

  • asm-tree-7.3.1.jar

  • asm-util-7.3.1.jar

Change the versions as appropriate.

The support for JavaScript scripts will be removed in the future. Please migrate any JavaScipt scripts to Groovy.

In contrast, scriptlets currently can only be used in a Simula template to produce output and to control logic (if…​else, loops, etc.). The scripting language supported for scriptlets is Groovy.

Script Executor

Executing a script is via a…​script executor. There are two possible ways to configure one - a separate, reusable instance of the script executor, or script executor specific to a script. The script executors are thread-safe so it is possible to define them outside of any script object - that will result in faster simulation startup time and reduced memory utilization.

ScriptExecutorName:
  is: scriptExecutor
  lang: javascript | groovy
  # Optional list of directories with script libraries
  libs:
  - "<directory1 with script libraries>"
  #...
  - "<directoryN with script libraries>"

The libs list elements can be absolute file paths, or paths with respect to the directory of the simulation, the directory with all simlets, or simlet’s directory as given by the global variables ${sim.path}, ${simlets.path}, and ${simlet.path}, respectively.

If a script doesn’t have script executor defined, then the script executor is assumed to be Groovy script executor and that it is specific to the script.

Scripts

JavaScript

#...

CardNumber:
  is: parameter
  from: body
  element: ".payer.funding_instruments[0].credit_card.number"

#...

JavascriptExecutor:
  is: scriptExecutor
  lang: javascript
  libs:
  - "${sim.path}/scripts"

maskCardNumberScript1:
  is: script
  # Reference to a reusable script executor instance
  executor: JavascriptExecutor
  # Call a function declared in an external library
  expression: "maskCardNumber('CardNumber', 'x', 4)"

maskCardNumberScript2:
  is: script
  # Script executor specific to this script
  executor:
    lang: javascript
    libs:
    - "${sim.path}/scripts"
  expression: "maskCardNumber('CardNumber', 'x', 4)"

Groovy

#...

CardNumber:
  is: parameter
  from: body
  element: ".payer.funding_instruments[0].credit_card.number"

#...

GroovyScriptExecutor:
  is: scriptExecutor
  lang: groovy
  libs:
  - "${sim.path}/scripts"

maskCardNumberScript1:
  is: script
  # Reference to a reusable script executor instance
  executor: GroovyScriptExecutor
  expression: "maskCardNumber('CardNumber', 'x', 4)"

maskCardNumberScript2:
  is: script
  # Script executor specific to this script. Optional.
  executor:
    lang: groovy
    libs:
    - "${sim.path}/scripts"
  expression: "maskCardNumber('CardNumber', 'x', 4)"

Script Expression

The expression can reference a function/method defined in a script library or it can contain the actual code. Notice the indentation of the script’s code in this contrived example:

# Multi-line inlined script
padZip5Plus4Script:
  is: script
  executor: javascriptExecutor
  expression: `
function padZipCode() {
  var zipCode = '' + _context.get('BillingAddressPostalCode');
  if (zipCode && zipCode.length == 5) {
    zipCode = zipCode + '-0000';
  }
  return zipCode;
}
padZipCode();
`

Scripted Parameters

Scripted Parameters are parameters which values are the result from executing a script. API Simulator supports the JavaScript and Groovy scripting languages.

Notice that a similar result can be achieved using Groovy scripting in an eval expression.

Here is an example of a scripted parameter:

request:
# ....

# Matcher for a Parameter
- where: parameter
  named: ProfileID
  equals: "Profile-123"


# A parameter with all the cookies
HttpCookies:
  is: parameter
  from: header
  named: "Cookie"

# This parameter value is the results from executing a script.
# Notice that what the script does - extracting a cookie by
# name - is just for demo purposes. This is much easier using
# the built-in support for parameters from cookies.
ProfileID:
  is: parameter
  from: script
  executor:
    # 'groovy' is also supported as the scripting language
    lang: javascript
  expression: `
function getCookieValue(name)
{
  // The value from the context is an object so must convert it to string
  var cookies = "" + _context.getValue('HttpCookies');

  // The rest of the code is from https://www.quirksmode.org/js/cookies.html
  var nameEQ = name + "=";
  var ca = cookies.split(';');
  for(var i=0;i < ca.length;i++) {
    var c = ca[i];
    while (c.charAt(0)==' ') c = c.substring(1,c.length);
    if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
  }
  return null;
}
getCookieValue("profile_id");
`
# ...

Scripted Matchers

The support for Scripted Matchers is through matcher for scripted parameter. See the example in the Scripted Parameters section.

Script Results Placeholders

In the following simlet configuration excerpt, MaskedCardNumber is a parameter used in a placeholder for the result from executing a script:

GroovyScriptExecutor:
  is: scriptExecutor
  lang: groovy
  libs:
  - "${sim.path}/scripts"

# This calls a function defined in an external script
MaskCardNumberScript:
  is: script
  executor: GroovyScriptExecutor
  expression: "maskCardNumber('x', 4)"


MaskedCardNumber:
  is: parameter
  from: script
  script: "MaskCardNumberScript"


response:
  from: template
  template: Simula

  status: 201
  headers:
  - "Content-Type: application/json; charset=UTF-8"

  body: `
{
  ...
  "funding_instruments": [
    {
      "credit_card": {
        ...
        "number": "${MaskedCardNumber}",
        ...
      }
    }
  ]
}
`

See also the scripting examples included in the Standalone API Simulator’s distro.


We would love to hear your feedback - send us a quick email to [feedback at APISimulator.com]

Happy API Simulating!