Calling Web Services in TransForm Forms from the Web Filler

Description

Other account settings is used to define request templates for making web service calls using the ajaxSendRequestFromServer() function.

Calls to third party services can be made using TPL's ajaxGET() and ajaxSendRequest() methods. Both methods make a request to the specified URL directly from the filler application. If the service requires API keys or other forms of authentication sent as either the request URL or body, credentials are included in the call.

TPL is executed client side. In the web filler, this means your API credentials can potentially be exposed to the end user. All modern web browsers include debugging tools which can be used to access the underlying code implementing a web page. TPL code is no exception and can be seen as clear text in the web filler.

To avoid exposing API keys and other credentials in the web filler, use the new ajaxSendRequestFromServer() function. ajaxSendRequestFromServer() is a new TPL function that makes calls to web services on the server instead of the client using Request Templates. Request Templates specify the URL to call, the method to use (e.g. GET, POST), required query parameters, and the body template for making the web service call. You can create a Request Template in Other account settings on the Home tab.

Other account settings
Other account settings

Other account settings is a JSON definition for creating Request Templates. For example, the following JSON defines a Request Template called getUsers that makes a GET request against the JSON Placeholder API's users endpoint (https://jsonplaceholder.typicode.com/users):

{
    "sendrequest": {
        "templates": {
            "getUsers": {
                "method": "GET",
                "url": "https://jsonplaceholder.typicode.com/users"
            }
        }
    }
}

When calling the endpoint using ajaxSendRequestFromServer(), the Request Template name is passed as the first parameter to the function. For example:

r = ajaxSendRequestFromServer("getUsers")

ajaxSendRequestFromServer() returns an object with details about the call outcome. The object can have the following properties:

Property
Description
error

If an error occurred calling the web service, error contains details about why the call failed. Otherwise, error will be an empty string.

status

If error is blank, contains the call result status.

timeout

The timeout in milliseconds specified for the request. Timeout defaults to 10000, but can be set in the Request Template to another value.

responseText

The content returned by the request.

Specifying a Request Template

A request template is a named object defined in the templates portion of the sendrequest object. For example:

{
    "sendrequest": {
        "templates": {
            "getUsers": {
                "method": "GET",
                "url": "https://jsonplaceholder.typicode.com/users"
            }
        }
    }
}

The request template defines the following properties:

Property
Description
method

String. The type of request operation. Can be one of "GET", "POST", "PUT", "DELETE", or "HEAD". Defaults to "GET" when no body is defined or "POST" when body is defined.

timeout

Number. Optional. The amount of time to wait in milliseconds before the request is assumed to have timed out. Defaults to 10000 if not set or is set to a value of 0.

url

String. Required. The request URL.

query

String or array of strings and objects. Optional. Query parameters to include in the request. Multiple query parameters must be separated with an ampersand &. See Defining Request Template Query Parameters, Headers, and Body.

headers

String or array of strings and objects. Optional. Additional headers to include in the request. Multiple headers must be separated with a new line \n. See Defining Request Template Query Parameters, Headers, and Body.

body

String or array of strings and objects. Optional. The body portion to include in the request.

Defining Request Template Query Parameters, Headers, and Body Content

Query parameters, headers, and body content are specified as either a string

"query":"state=MA&city=Boston"

Or an array of strings or objects defining how the value is computed using the following format:

{
    "type": valueType,
    "value": valueSource,
    "filter": filterType
}

For example, the string for the query "state=MA&city=Boston" could be written as two objects:

"query": [
    {
        "type":"string",
        "value":"state=MA"
    },
    {
        "type":"string",
        "value":"&city=Boston"
    }
]

type can be one of three values:

Value
Description
string

The value is a string.

arg

The value is an argument passed to ajaxSendRequestFromTemplate(). See Passing Arguments to ajaxSendRequestFromServer().

constant

The value is a constant, defined in the constants portion of the sendrequest definition. See Using Constants.

Depending on the specified type, value can be one of the following:

Value
Description
A string

If type is "string", then the content of value is included verbatim.

A number

If type is "arg", value is a number indicating which argument passed to ajaxSendRequstFromTemplate() to include. E.g. "value":2 would include the value of the second argument passed to ajaxSendRequestFromTemplate().

The name of a constant

If type is "constant", value is the name of the constant to include. E.g. "value":"myAPIKey". See Using Constants.

You can specify an optional filter to process the value before including it in the query string, header, or body. Two filters are available:

Value
Description
alphanumeric

Strips all characters out of the string that are not numbers or letters.

jsescape

Escapes characters in the string (such as double quotes ") to make the content safe to include in a JSON object. Useful when building a JSON string that will be sent as the body of the web service call.

The strings and objects are concatenated together to form the value for the query parameters, headers, or body. For example:

"body": [
    "This is a string",
    { "type":"arg","value":1},
    "This is a string"
]

This produces the following string when the ajaxSendRequestFromServer() is called with the value "This is an argument" passed as the first argument to the function:

This is a stringThis is an argumentThis is a string

Note that the string does not contain any line breaks. Line breaks are added using the special "\n" escape character. "\n" is JavaScript for a new line (line break). For example:

"body": [
    "This is a string",
    "\n",
    {"type":"arg","value":1},
    "\n",
    "This is a string"
]

With the addition of new lines, the generated string for the body is now:

This is a string
This is an argument
This is a string

When defining headers, line breaks are required after each header entry if you plan to include more than one header. For example, "\n" is included at the end of the first two strings in the headers array to insert a new line after the header value:

"header": [
    "x-api-key:API_KEY_HERE\n",
    "Content-Type:application/json; charset=utf-8\n",
    "Access-Control-Allow-Origin:http://example.org"
]

If the value included is computed from an argument or constant, you can add new lines as individual entries in the array. You can also include them separately for improved readability after strings. For example:

"header": [
    {
        "type":"constant",
        "value":"myAPIKey"
    },
    "\n",
    "Content-Type: application/json; charset=utf-8",
    "\n",
    "Access-Control-Allow-Origin: http://example.org"
]

Passing Arguments to ajaxSendRequestFromServer()

If your request requires additional information gathered from the form, it can be passed to the request as arguments when using ajaxSendRequestFromServer(). Arguments can be passed as an array or a comma-delimited list of values after the template name in ajaxSendRequestFromServer()

Syntax

ajaxSendRequestFromServer(templateName, arguments_array)

ajaxSendRequestFromServer(templateName, arg1, arg2, arg3, ...)

Arguments are referenced in the order they're passed to the function. If passed as an array, the first value in the array is argument 1, the second argument 2, and so on. If passed as a comma delimited list of values, the first value is argument 1, the second argument 2, etc.

Arguments can be used in the Request Template to populate query strings, headers, or the body. For example:

{
    "sendrequest": {
        "templates": {
            "createPost": {
                "method": "POST",
                "url": "https://jsonplaceholder.typicode.com/posts",
                "headers": "Content-type: application/json; charset=UTF-8",
                "body": [
                    "{\"title\":\"",
                    {
                        "type": "arg",
                        "value": 1
                    },
                    "\",",
                    "\"body\":\"",
                    {
                        "type": "arg",
                        "value": 2
                    },
                    "\",",
                    "\"userid\":",
                    {
                        "type": "arg",
                        "value": 3
                    },
                    "}"
                ]
            }
        }
    }
}

In the example request template above, createPost, the body is created dynamically from three arguments. When executing the createPost request, the arguments could be passed to the request template as an array, shown in the example TPL function below:

FUNCTION @createPost
    arguments = array()
    arrayPush(arguments, "My Title")
    arrayPush(arguments, "My Message")
    arrayPush(arguments, "3")

    r = ajaxSendRequestFromServer("createPost", arguments)

    if (r.error)
        msgShowWarning("Error doing Send Request Server", r.error)
        return
    endif
    return r.responseText
ENDFUNCTION

If fewer arguments are supplied than required by the request, the missing arguments will resolve to a blank value.

Using Constants

You can create constants that can be used in web service calls. Constants are useful for defining commonly used strings, such as headers, storing API credentials, and other commonly used in your Request Templates.

Constants are defined as a sibling to "template". For example:

{
    "sendrequest": {
        "templates": {
            ...
        },
        "constants": {
            "name": "value",
            "name2": "value2",
            ...
        }
    }
}

Each constant is defined as a "name":"value" pair. The name is the name referenced in the Request Template in the value property for a query parameter, header, or body array entry. The value is a string inserted into the Request Template where referenced.

If you reference a constant that doesn't exist, the constant will resolve to a blank value.

How to Convert a JSON body into an array for use in ajaxSendRequestFromServer()

Many web services accept data posted to an endpoint in the form of JSON in the body of the request. JSONPlaceholder is a fake API for testing and prototyping. We will use the /posts JSONPlaceholder endpoint in this exercise to demonstrate how to convert the JSON for a request body into a format required by a TransForm Request Template.

The JSONPlaceholder /posts endpoint (https://jsonplaceholder.typicode.com/posts) is a POST request that creates a new post (i.e. blog post) for a user. The post is submitted to the endpoint as JSON in the body. For example:

{
    "title": "My Title",
    "body": "This is the post body",
    "userId": "1"
}

title, body, and userId are the parameters that specify the post title, body, and the user that created the post for the /posts endpoint. "My Title", "this is the post body", and 1 are the values for those parameters.

  1. Convert the JSON into a comma-delimited list of strings. Escape any double quotation marks and backslashes with a backslash. E.g. "\"" for double quotes and "\\" for backslashes. Use \n to include line breaks in the strings if required.

    [
        "{",
        "\"title\": \"My Title\",",
        "\"body\": \"This is the post body\",",
        "\"userId\": \"1\"",
        "}"
    ]
  2. Replace string values that you would like to set dynamically using arguments or constants with objects:

    [
        "{",
        "\"title\": \"",
        {
            "type":"string",
            "value":"My Title"
        },
        "\",",
        "\"body\": \"",
        {
            "type":"string",
            "value":"This is the post body"
        },
        "\",",
        "\"userId\":",
        {
            "type":"string",
            "value":"1"
        },
        "}"
    ]
  3. Add in your arguments, constants, and filters where you'd like them to be used:

    [
        "{",
        "\"title\": \"",
        {
            "type":"arg",
            "value": 1,
            "filter":"jsescape" /*Optional*/
        },
        "\",",
        "\"body\": \"",
        {
            "type":"arg",
            "value": 2,
            "filter":"jsescape" /*Optional*/
        },
        "\",",
        "\"userId\":",
        {
            "type":"constant",
            "value":"userId"
        },
        "}"
    ]
  4. Create the Request Template and Constants JSON and save it in Other account settings:

    {
        "sendrequest": {
            "templates": {
                "createPost":{
                    "method":"POST",
                    "url":"https://jsonplaceholder.typicode.com/posts",
                    "headers":"Content-type: application/json; charset=UTF-8",
                    "body":[
                        "{",
                        "\"title\": \"",
                        {
                            "type":"arg",
                            "value": 1,
                            "filter":"jsescape"
                        },
                        "\",",
                        "\"body\": \"",
                        {
                            "type":"arg",
                            "value": 2,
                            "filter":"jsescape"
                        },
                        "\",",
                        "\"userId\":",
                        {
                            "type":"constant",
                            "value":"userId"
                        },
                        "}"
                    ]
                }
            },
            "constants": {
                "userId": "1"
            }
        }
    }
  5. Call the request from TPL:

    FUNCTION @createPost
        arguments = array()
        arrayPush(arguments, "My Title")
        arrayPush(arguments, "This is the post body")
    
        r = ajaxSendRequestFromServer("createPost", arguments)
    
        if (r.error)
            msgShowWarning("Error doing Send Request Server", r.error)
            return
        endif
        return r.responseText
    ENDFUNCTION

Common Error Messages

If an error occurs when calling ajaxSendRequestFromServer(), an error message may be returned. Some common error messages seen are described below:

Error
Description
No url

The Request Template doesn't exist or doesn't define the url property.

Common Statuses

If error is blank, it doesn't mean the request didn't fail. status contains an HTTP status code for the request. The status code indicates whether or not the request succeeded. Some common status codes are listed below:

Status Code
Description
200

The request succeeded.

201

The request succeeded and a resource was created.

301

The endpoint has moved to a new permanent location.

302

The endpoint has moved temporarily.

400

The request cannot be completed due to an issue with how the request was sent. For example, a missing query parameter.

401

Unauthorized. Typically sent when authentication has not been provided and is required.

403

You don't have permission to access the endpoint.

404

The endpoint doesn't exist.

405

You are not allowed to make requests to the endpoint.

429

Too many requests have been made to the endpoint in a given time period. This is usually seen with APIs that impose rate limiting.

500

The server hosting the web service encountered a situation it doesn't know how to handle.

If you receive a 3xx, 4xx, or 5xx status, the request failed. See HTTP response status codes (MDN) for more detailed information about HTTP status codes and their meanings.

Handling 3xx Responses

ajaxSendRequestFromServer() does not return detailed response information for 3xx requests. For example, if you get a 301 response, no additional information is provided in the response.

Example 301 result:

{
  "error":"",
  "status":"301",
  "timeout":10000,
  "responseText":""
}

If you receive a 3xx response, you will need to consult your API documentation to determine the new endpoint or use a third-party tool to execute the request and get the full text of the response, which usually contains the location where the endpoint has moved.

Handling 4xx Responses

If you receive a 4xx status, it means something is incorrect with the request. For example, the endpoint doesn't exist (404), you don't have permissions to access the endpoint (403), or you didn't include your access credentials (401). Consult your API documentation for information about 4xx status codes and how to resolve them.

Handling 5xx Responses

A 5xx response often indicates something is wrong with the server hosting the web service. Contact your API provider if you receive a 5xx response status.

See Also