Creating a Prototype API with Mock Payload Generated Inline Scripts

The prototype implementation in WSO2 API Manager gives users the ability to prototype APIs with inline scripts for testing purposes and as an early promotion. This allows subscribers to try out and test APIs without subscriptions or monetizations, allowing them to provide feedback to improve APIs. Publishers can use this to make changes to the APIs requested by users. The WSO2 API Manager prototype implementation allows you to generate a mock payload based on an API definition. You can prototype an API using the inbuilt JavaScript engine without having to manually write the JavaScript implementation for each resource.

Let's create a prototyped API with mock response payloads, deploy it as a prototype, and invoke it using the API Console, which is integrated into the Developer Portal.

For this let's use the following OpenAPI URL: https://petstore.swagger.io/v2/swagger.json

Step 1 - Create a prototype API with mock response payloads

  1. Click CREATE NEW API, and click I Have an Existing REST API.

    Create API options

  2. Upload the OpenAPI URL or OpenAPI File and click NEXT.

    Filled create api form for existing

  3. Provide the API name, context, and version. Thereafter, click CREATE.

    Filled create api form

    You are directed to the API overview page.

  4. Click Endpoints to navigate to the Endpoints page.

  5. Select Prototype Implementation as the endpoint type, and click ADD.

    Selecting Prototype Implementation to add

    The Endpoints page appears.

    List of endpoints in Inline script page

  6. Click and expand any of the methods that contain a sample/mock payload to view the inline script that has been generated.

    Generated inline script

    The example response defined in the OpenAPI definition is set as the mock response payload. You can modify the generated inline scripts as required.

    var response200json = [ {                             // Mock response payload stored as a variable
      "id" : 0,
      "category" : {
        "id" : 0,
        "name" : "string"
      },
      "name" : "string",
      "photoUrls" : [ "string" ],
      "tags" : [ {
        "id" : 0,
        "name" : "string"
      } ],
      "status" : "available"
    } ]                                                 
    
    mc.setProperty('CONTENT_TYPE', 'application/json');  // Set the content type of the payload to the message context 
    mc.setPayloadJSON(response200json);                  // Set the new payload to the message context
  7. Modify the inline script for /pet/{petId}.

    Set a path parameter entered by the user to a variable that will satisfy a condition and set a response accordingly.

    Tip

    The RESET button appears after a change is made to the script. When pressed, the script will revert back to the originally generated script.

    Modified inline script

    // **GENERATED CODE** //
    
    var response200json = [ {                            // Mock response payload stored as a variable
      "id" : 0,
      "category" : {
        "id" : 0,
        "name" : "string"
      },
      "name" : "string",
      "photoUrls" : [ "string" ],
      "tags" : [ {
        "id" : 0,
        "name" : "string"
      } ],
      "status" : "available"
    } ]                                                 
    
    // **MANUALLY ADDED CODE** //
    
    if (mc.getProperty('uri.var.petId') == 1) {          // Get the path parameter 'petID' to check the condition
      response200json = {
        "id" : 1,
        "category" : {
          "id" : 1,
          "name" : "Dog"
        },
        "name" : "doggie",
        "photoUrls" : [ "string" ],
        "tags" : [ {
          "id" : 1,
          "name" : "German Sheperd"
        } ],
        "status" : "available"
      }
    }
    
    mc.setProperty('CONTENT_TYPE', 'application/json');  // Set the content type of the payload to the message context 
    mc.setPayloadJSON(response200json);                  // Set the new payload to the message context
    

    Inline Script Methods

    The following table lists down the mc. methods that you can use to invoke functions in the inline script. You can use these functions to access the Synapse predefined in a script variable named mc. The mc variable represents an implementation of the MessageContext, named ScriptMessageContext.java, which contains the following methods, that you can access within the script as mc.methodName.

    Return? Method Name Description
    Yes getPayloadXML() This gets an XML representation of SOAP body payload.
    No setPayloadXML(payload) This sets the SOAP body payload from XML.
    Yes getEnvelopeXML() This gets the XML representation of the complete SOAP envelope.
    No setTo(reference) This is used to set the value that specifies the receiver of the message.
    Yes setFaultTo(reference) This is used to set the value that specifies the receiver of the faults relating to the message.
    No setFrom(reference) This is used to set the value that specifies the sender of the message.
    No setReplyTo(reference) This is used to set the value that specifies the receiver of the replies to the message.
    Yes getPayloadJSON() This gets the JSON representation of a SOAP Body payload.
    No setPayloadJSON( payload ) This sets the JSON representation of a payload obtained via the getPayloadJSON() method and sets it in the current message context.
    Yes getProperty(name) This gets a property from the current message context.
    No setProperty(key, value) This is used to set a property in the current message context. The previously set property values are replaced by this method.
  8. Click SAVE to save the API.

    Save button Inline scripts page

Step 2 - Deploy the API as a prototype

  1. Click Lifecycle to navigate to the Lifecycle page.

  2. Click DEPLOY AS A PROTOTYPE to deploy the API as a prototype.

    Lifecycle page

Step 3 - Invoke the API

  1. Click View in Dev Portal to navigate to the Developer Portal after the API is deployed.

  2. Click Try Out to navigate to the API Console.

    Devportal overview

  3. Expand any method and click Try it out.

    Tryout click

  4. Enter the value for the parameter and click Execute to invoke the API.

    Note that the payload that you gave as a JSON/XML output appears in the response for each respective parameter provided.

    1. For petId : " 0 "

      Tryout for petid0

      The response payload that is defined in the generated script is returned.

      Response for petid0

    2. For petId : " 1 "

      Tryout for petid1

      The response payload defined in the manually modified script is returned.

      Response for petid1

You have successfully created an API with an inline script, deployed it as a prototype, and invoked it via the integrated API Console.

An API can also be prototyped by moving the API to the PROTOTYPED state by changing the API lifecycle state and providing the prototype endpoints.

For more information, see the Deploy and Test Prototype APIs tutorial.

Restricting Access to Java Classes and Methods

Update Level 257

This feature is available only as an update, after Update level 3.1.0.257

Java Classes and Methods are visible to the prototype scripts by default.

For example,

  • var myArrayList = new java.util.ArrayList(); would instantiate a Java Arraylist.
  • var hashmapConstructors = c.getClassLoader().loadClass("java.util.HashMap").getDeclaredConstructors(); would get a list of constructors of Java HashMap via reflection.

Usage of classes or methods in such manner can be restricted by using the following configs/system properties.

Limiting Access to Java Classes

Set the limit_java_class_access_in_scripts configurations under synapse_properties in the deployment.toml, following either a BLOCK_LIST approach (selectively blocking) or an ALLOW_LIST approach (selectively allowing).

Synapse Property Description Example Values
limit_java_class_access_in_scripts.enable Enable limiting access to Java classes. true
false
limit_java_class_access_in_scripts.class_prefixes Prefixes of Java class names, as comma separated values. Java Classes used in the script, having names beginning with these values, will be selectively allowed/blocked, based on the provided limit_java_class_access_in_scripts.list_type. java.util
java.lang
limit_java_class_access_in_scripts.list_type Type of the list. Possible values are:
- ALLOW_LIST: Selectively allow
- BLOCK_LIST: Selectively block
ALLOW_LIST
BLOCK_LIST

Example Config:

[synapse_properties]
'limit_java_class_access_in_scripts.enable' = true
'limit_java_class_access_in_scripts.list_type' = "ALLOW_LIST"
'limit_java_class_access_in_scripts.class_prefixes' = "java.util"
The above configuration uses an Allow Listing approach. This would only allow using the classes of which - the name starts with java.util, within the script. Usage of any other classes would result in an error as shown below:

Script Content:

print(java.lang.Math.pow(3, 2));
Output during API Execution
ERROR - ScriptMediator {api:Mock:v1.0.0} The script engine returned an error executing the inlined js script function mediate
com.sun.phobos.script.util.ExtendedScriptException: org.mozilla.javascript.EcmaError: TypeError: Cannot call property pow in object [JavaPackage java.lang.Math]. It is not a function, it is "object". (<Unknown Source>#3) in <Unknown Source> at line number 3

Limiting Access to Java Methods/Native Objects

Set the following system properties at server start up, following either a BLOCK_LIST approach (selectively blocking) or an ALLOW_LIST approach (selectively allowing).

System Property Description Example Values
limitJavaNativeObjectAccessInScripts.enable Enable limiting access to Java methods/native objects. true
false
limitJavaNativeObjectAccessInScripts.objectNames Names of Java methods/native objects, as comma separated values. Java Methods/native objects used in the script having these names will be selectively allowed/blocked, based on the provided limitJavaNativeObjectAccessInScripts.listType. getClassLoader
getClass
limitJavaNativeObjectAccessInScripts.listType Type of the list. Possible values are:
- ALLOW_LIST: Selectively allow
- BLOCK_LIST: Selectively block
ALLOW_LIST
BLOCK_LIST

Example Config:

./bin/wso2server.sh -DlimitJavaNativeObjectAccessInScripts.enable=true -DlimitJavaNativeObjectAccessInScripts.listType=BLOCK_LIST -DlimitJavaNativeObjectAccessInScripts.objectNames=getClassLoader,loadClass
The above configuration uses a Block Listing approach. This would not allow the usage of getClassLoader() method within the script.

Script Content:

var hashmapConstructors = c.getClassLoader().loadClass("java.util.HashMap").getDeclaredConstructors()

Output during API Execution:

ERROR - ScriptMediator {api:Mock:v1.0.0} The script engine returned an error executing the inlined js script function mediate
com.sun.phobos.script.util.ExtendedScriptException: org.mozilla.javascript.EcmaError: TypeError: Cannot find function getClassLoader in object class javax.script.SimpleScriptContext. (<Unknown Source>#21) in <Unknown Source> at line number 21

Top