Resolving INVALID_FUNCTION in CXone Studio Snippets: Correct Syntax for GetRESTProxy()

Resolving INVALID_FUNCTION in CXone Studio Snippets: Correct Syntax for GetRESTProxy()

What You Will Build

  • You will build a working CXone Studio Snippet that executes an external HTTP GET request using the GetRESTProxy() function.
  • This tutorial uses the NICE CXone Studio Snippet engine (JavaScript-based runtime) to interact with external APIs.
  • The primary language covered is JavaScript (ES6+) within the CXone Studio Snippet context.

Prerequisites

  • Access Level: Developer or Administrator access to the NICE CXone Platform.
  • Studio Access: Ability to edit Studio Flows and Snippets.
  • External API Target: A valid public URL or internal service URL that accepts HTTP GET requests (e.g., https://jsonplaceholder.typicode.com/todos/1).
  • Studio Snippet Knowledge: Basic understanding of how Studio Snippets function as reusable logic blocks within Studio Flows.
  • Debugging Tools: Access to the Studio Debug Mode or Execution Logs to inspect runtime errors.

Authentication Setup

Studio Snippets run within the context of the NICE CXone platform. Unlike external SDKs, you do not configure OAuth tokens manually in the snippet code. The snippet inherits the authentication context of the Studio Flow execution.

However, if the external API you are calling requires authentication (such as a private REST endpoint), you must handle that within the GetRESTProxy configuration or via pre-computed headers. For this tutorial, we assume the target API is public or uses API keys passed in headers.

If you are testing this locally before deploying to Studio, you cannot test the GetRESTProxy function directly in a local Node.js environment because it is a proprietary CXone runtime function. You must deploy the snippet to the CXone environment and trigger it via a Studio Flow or the Studio Debug Console.

Implementation

Step 1: Understanding the INVALID_FUNCTION Error

The INVALID_FUNCTION error in CXone Studio Snippets typically occurs when the JavaScript engine cannot resolve a function name. In the context of GetRESTProxy, this error usually stems from one of three causes:

  1. Typographical Errors: The function is misspelled (e.g., GetRestProxy, getRESTProxy, GetRESTProxyy). JavaScript is case-sensitive.
  2. Context Mismatch: Attempting to call GetRESTProxy in a context where it is not available (e.g., inside a pure JavaScript library import that is not part of the Studio runtime environment).
  3. Incorrect Invocation Syntax: Passing arguments in a format the engine does not expect, causing the runtime to fail binding the function.

The correct function name is GetRESTProxy. It is a global function within the Studio Snippet execution context.

Step 2: Basic Syntax and Structure

The GetRESTProxy() function returns a proxy object that allows you to configure and execute HTTP requests. The standard pattern involves:

  1. Calling GetRESTProxy().
  2. Configuring the request method, URL, headers, and body.
  3. Executing the request.
  4. Handling the response.

Here is the minimal valid syntax for a GET request:

// Correct invocation
var proxy = GetRESTProxy();

// Configure the request
proxy.setMethod("GET");
proxy.setUrl("https://jsonplaceholder.typicode.com/todos/1");

// Execute the request
var response = proxy.execute();

// Parse the response
var data = JSON.parse(response.getBody());

// Return the result to the Studio Flow
return {
    "status": response.getStatusCode(),
    "data": data
};

Step 3: Implementing a Robust GET Request

A production-grade snippet must handle errors, timeouts, and parsing failures. The INVALID_FUNCTION error might also mask underlying issues if the previous line failed silently or if the function is not recognized due to a platform version mismatch (though GetRESTProxy has been stable for years).

Below is a complete, robust implementation of a Studio Snippet that performs a GET request.

Code Example: Robust GET with Error Handling

// Define the main function for the Studio Snippet
function main() {
    var result = {
        "success": false,
        "statusCode": null,
        "responseBody": null,
        "errorMessage": null
    };

    try {
        // 1. Instantiate the REST Proxy
        // This is the critical line. If this throws INVALID_FUNCTION, 
        // check for typos or platform compatibility.
        var proxy = GetRESTProxy();

        // 2. Configure the Request
        var targetUrl = "https://jsonplaceholder.typicode.com/todos/1";
        
        // Set HTTP Method
        proxy.setMethod("GET");
        
        // Set URL
        proxy.setUrl(targetUrl);

        // 3. Set Headers (Optional but recommended for tracking)
        // CXone Studio allows dynamic header injection
        proxy.setHeader("User-Agent", "CXone-Studio-Snippet/1.0");
        proxy.setHeader("Accept", "application/json");

        // 4. Set Timeout (in milliseconds)
        // Default is often 5000ms, but explicit is better
        proxy.setTimeout(10000);

        // 5. Execute the Request
        // This blocks until the response is received or timeout occurs
        var response = proxy.execute();

        // 6. Process the Response
        var statusCode = response.getStatusCode();
        var responseBody = response.getBody();
        var headers = response.getHeaders();

        result.statusCode = statusCode;

        // Check for HTTP Success (2xx)
        if (statusCode >= 200 && statusCode < 300) {
            try {
                // Attempt to parse JSON
                var parsedData = JSON.parse(responseBody);
                result.success = true;
                result.responseBody = parsedData;
            } catch (parseError) {
                // If JSON parsing fails, return raw body
                result.success = true;
                result.responseBody = responseBody;
                result.errorMessage = "JSON Parse Error: " + parseError.message;
            }
        } else {
            // HTTP Error (4xx, 5xx)
            result.success = false;
            result.responseBody = responseBody;
            result.errorMessage = "HTTP Error: " + statusCode;
        }

    } catch (e) {
        // Catch any runtime errors, including INVALID_FUNCTION
        result.success = false;
        result.errorMessage = "Runtime Error: " + e.message;
        
        // Log the error for debugging in Studio Execution Logs
        console.error("Studio Snippet Error:", e);
    }

    // Return the structured result to the Studio Flow
    return result;
}

// Ensure the function is exported if required by specific snippet types
// In standard Studio Snippets, the 'main' function is auto-detected

Step 4: Handling POST Requests with JSON Payloads

The INVALID_FUNCTION error can also appear if you attempt to use non-existent methods on the proxy object. For example, proxy.setBody() is the correct method, not proxy.setPayload().

Here is how to correctly structure a POST request:

function main() {
    var result = {
        "success": false,
        "statusCode": null,
        "responseBody": null,
        "errorMessage": null
    };

    try {
        var proxy = GetRESTProxy();
        
        // Target API
        var targetUrl = "https://httpbin.org/post";
        
        // Set Method
        proxy.setMethod("POST");
        proxy.setUrl(targetUrl);

        // Set Headers
        proxy.setHeader("Content-Type", "application/json");
        proxy.setHeader("Accept", "application/json");

        // Set Body
        // The body must be a string. JSON.stringify is essential.
        var payload = {
            "username": "developer_test",
            "action": "create_record",
            "timestamp": new Date().toISOString()
        };
        
        proxy.setBody(JSON.stringify(payload));

        // Set Timeout
        proxy.setTimeout(10000);

        // Execute
        var response = proxy.execute();

        var statusCode = response.getStatusCode();
        result.statusCode = statusCode;

        if (statusCode >= 200 && statusCode < 300) {
            var responseBody = response.getBody();
            result.success = true;
            try {
                result.responseBody = JSON.parse(responseBody);
            } catch (e) {
                result.responseBody = responseBody;
            }
        } else {
            result.success = false;
            result.errorMessage = "HTTP Error: " + statusCode;
            result.responseBody = response.getBody();
        }

    } catch (e) {
        result.success = false;
        result.errorMessage = "Runtime Error: " + e.message;
        console.error("POST Request Failed:", e);
    }

    return result;
}

Complete Working Example

Below is a complete Studio Snippet that you can copy and paste directly into the CXone Studio Snippet editor. This snippet includes both GET and POST capabilities controlled by an input parameter.

Input Parameters Expected by Studio Flow:

  • method: String (“GET” or “POST”)
  • url: String (The target URL)
  • payload: String (Optional JSON string for POST)

Studio Snippet Code:

/**
 * CXone Studio Snippet: Universal REST Client
 * 
 * Inputs:
 * - method: String (GET, POST, PUT, DELETE)
 * - url: String (Target URL)
 * - payload: String (Optional JSON body for POST/PUT)
 * 
 * Outputs:
 * - success: Boolean
 * - statusCode: Number
 * - responseBody: Object or String
 * - errorMessage: String
 */

function main() {
    var result = {
        "success": false,
        "statusCode": null,
        "responseBody": null,
        "errorMessage": null
    };

    // Retrieve inputs from the Studio Flow context
    // Note: In Studio, inputs are passed via the flow context. 
    // Depending on how you configure the snippet, these might be 
    // accessed via global variables or function arguments.
    // Standard practice: Studio passes inputs as properties of the input object.
    // However, in the snippet editor, we often define the main function 
    // and access inputs via the 'input' object if configured, 
    // or we hardcode for testing. 
    // For this tutorial, we will assume the inputs are passed as arguments 
    // or accessed from a global 'input' context provided by the platform.
    
    // If using Studio's standard snippet input mapping:
    var method = input.method || "GET";
    var url = input.url || "https://jsonplaceholder.typicode.com/todos/1";
    var payload = input.payload || null;

    // Validate inputs
    if (!url) {
        result.errorMessage = "URL is required.";
        return result;
    }

    try {
        // 1. Initialize Proxy
        var proxy = GetRESTProxy();

        // 2. Configure Method and URL
        proxy.setMethod(method.toUpperCase());
        proxy.setUrl(url);

        // 3. Configure Headers
        proxy.setHeader("Accept", "application/json");
        
        // If payload exists, set Content-Type
        if (payload && method.toUpperCase() !== "GET") {
            proxy.setHeader("Content-Type", "application/json");
            proxy.setBody(payload);
        }

        // 4. Set Timeout
        proxy.setTimeout(15000); // 15 seconds

        // 5. Execute
        var response = proxy.execute();

        // 6. Parse Response
        var statusCode = response.getStatusCode();
        var responseBody = response.getBody();
        result.statusCode = statusCode;

        if (statusCode >= 200 && statusCode < 300) {
            result.success = true;
            try {
                result.responseBody = JSON.parse(responseBody);
            } catch (e) {
                // Return raw string if not JSON
                result.responseBody = responseBody;
            }
        } else {
            result.success = false;
            result.errorMessage = "HTTP Error: " + statusCode;
            try {
                result.responseBody = JSON.parse(responseBody);
            } catch (e) {
                result.responseBody = responseBody;
            }
        }

    } catch (e) {
        result.success = false;
        result.errorMessage = "Execution Error: " + e.message;
        // Log to Studio Execution Logs
        console.error("Universal REST Client Error:", e);
    }

    return result;
}

Common Errors & Debugging

Error: INVALID_FUNCTION at line X

What causes it:
The JavaScript engine cannot find the function GetRESTProxy. This is almost always a typo.

How to fix it:

  1. Check the spelling. It is GetRESTProxy, not GetRestProxy or getRESTProxy.
  2. Ensure you are not importing a library that shadows global functions.
  3. Verify that you are running this code in a CXone Studio Snippet context. This function does not exist in standard Node.js or browser JavaScript environments.

Error: TypeError: proxy.setMethod is not a function

What causes it:
GetRESTProxy() returned null or undefined, or the platform version is extremely outdated (unlikely in modern CXone).

How to fix it:
Add a null check immediately after instantiation:

var proxy = GetRESTProxy();
if (!proxy) {
    throw new Error("Failed to initialize REST Proxy");
}

Error: JSON Parse Error

What causes it:
The external API returned HTML (e.g., a 404 error page) or plain text instead of JSON, and you forced JSON.parse().

How to fix it:
Always wrap JSON.parse() in a try-catch block, as shown in the complete working example. Return the raw string if parsing fails.

Error: Timeout

What causes it:
The external API took longer than the default timeout (often 5-10 seconds) to respond.

How to fix it:
Increase the timeout using proxy.setTimeout(milliseconds).

proxy.setTimeout(30000); // 30 seconds

Official References