This page applies to Apigee and Apigee hybrid.
View Apigee Edge documentation.
This topic discusses the Apigee JavaScript Object Model. It's important to understand this model if you intend to use the JavaScript policy to add custom JavaScript to an API proxy.
About the JavaScript object model
The JavaScript object model defines objects with associated properties that are available to JavaScript code executing within an Apigee proxy flow. Use the JavaScript policy to attach this custom code to an API proxy flow.
The objects defined by this model have scope within the API proxy flow, which means that certain objects and properties are available only at specific points in the flow. When your JavaScript is executed, a scope is created for the execution. In that scope, these object references are created:
- context: An object that provides access to message context
- request: A shorthand that allows access to the request object
- response: A shorthand that allows access to the response object
- crypto: Provides various hash functions
- print: A function to emit output
- properties: Allows read access to the configuration properties on the policy
The context object
The context
object has global scope. It is available everywhere within the API
proxy flow. It has four child objects: proxyRequest
, proxyResponse
,
targetRequest
, targetResponse
. These child objects are scoped to the
ambient request and response, either the proxy request and response or the target request and
response. For example, if the JavaScript policy executes in the proxy endpoint part of the flow,
then the context.proxyRequest
and context.proxyResponse
objects are in
scope. If the JavaScript runs in a target flow, then the context.targetRequest
and
context.targetResponse
objects are in scope.
The context
object also has properties and methods, which are described in detail
in this topic. For example, the following JavaScript code example uses the
context.flow
property and calls the get/setVariable() methods on
context
.
if (context.flow=="PROXY_REQ_FLOW") { var username = context.getVariable("request.formparam.user"); context.setVariable("USER.name", username); }
These methods interact directly with
flow variables.
The context.flow
property value is the current flow scope. In the proxy
request flow, it's set to the constant PROXY_REQ_FLOW
. If in the target
response flow, it's set to TARGET_RESP_FLOW
. This constant is handy for
executing scope-specific code. The getter lets you get flow variables and the setter lets you set
flow variables. These variables are generally available in the proxy flow and can be consumed by
other policies.
See context object reference for more details and examples.
The crypto object
The crypto object adds basic, high performance cryptographic support to the JavaScript Object Model. See crypto object reference for more details and examples.
The request and response objects
The request
and response
objects are shorthand references to the
ambient request and response, either the proxy request and response or the target request and
response. The objects these variables refer to depend upon the context in which the JavaScript
policy executes. If the JavaScript runs in the flow of a proxy endpoint, then the request and
response variables refer to context.proxyRequest
and
context.proxyResponse
. If the JavaScript runs in a target flow, then the variables
refer to the context.targetRequest
and context.targetResponse
.
The print() function
The JavaScript object model includes a print() function that you can use to output debug information to the Apigee Debug tool. See Debug with JavaScript print() statements.
The properties object
When using a Properties
element in the policy configuration, the
JavaScript code can access the values of those properties using the
properties
variable.
For example, if your JavaScript configuration contains:
<Javascript name='JS-1' > <Properties> <Property name="number">8675309</Property> <Property name="firstname">Jenny</Property> </Properties> <ResourceURL>jsc://my-code.js</ResourceURL> </Javascript>
Then in my-code.js
, you can:
print(properties.firstname); // prints Jenny print(properties.number); // 8675309
More practically, configuration can allow the code to behave differently when run in different environments, at different moments, or for any reason.
For example, the following specifies the "variable name" and the style of output that the JavaScript should emit information into:
<Javascript name='JS-2' > <Properties> <Property name="output">my_output_variable</Property> <Property name="prettyPrint">true</Property> </Properties> <ResourceURL>jsc://emit-results.js</ResourceURL> </Javascript>
emit-results.js
, the code could do this:
var result = { prop1: "something", prop2 : "something else" } ; if (properties.prettyPrint == "true") { context.setVariable(properties.output, JSON.stringify(result, null, 2)); } else { context.setVariable(properties.output, JSON.stringify(result)); }
crypto object reference
The crypto object lets you perform basic cryptographic hashing functions in JavaScript.
The crypto object has global scope. It is available everywhere within the API proxy flow. Crypto lets you work with these hash objects:
- SHA-1
- SHA256
- SHA512
- MD5
Working with SHA-1 objects
You can create SHA-1 objects, update them, and convert them to hex and base64 values.
Create a new SHA-1 object
var _sha1 = crypto.getSHA1();
Update an SHA-1 object
Syntax
_sha1.update(value);
Parameters
- value - (String) Any string value.
Example
Update an SHA-1 object:
_sha1.update("salt_value"); _sha1.update("some text");
Return the SHA-1 object as a hex string
var _hashed_token = _sha1.digest();
Return the SHA-1 object as a base64 string
var _hashed_token = _sha1.digest64();
Working with SHA-256 objects
You can create SHA-256 objects, update them, and convert them to hex and base64 values.
Create a new SHA-256 object
var _sha256 = crypto.getSHA256();
Update an SHA-256 object
Syntax
_sha256.update(value);
Parameters
- value - (String) Any string value.
Example
Update an SHA-256 object:
_sha256.update("salt_value"); _sha256.update("some text");
Return the SHA-256 object as a hex string
var _hashed_token = _sha256.digest();
Return the SHA-256 object as a base64 string
var _hashed_token = _sha256.digest64();
Working with SHA-512 objects
You can create SHA-512 objects, update them, and convert them to hex and base64 values.
Create a new SHA-512 object
var _sha512 = crypto.getSHA512();
Update an SHA-512 object
Syntax
_sha512.update(value);
Parameters
- value - (String) Any string value.
Example
Update an SHA-512 object:
_sha512.update("salt_value"); _sha512.update("some text");
Return the SHA-512 object as a hex string
var _hashed_token = _sha512.digest();
Return the SHA-512 object as a base64 string
var _hashed_token = _sha512.digest64();
Working with MD5 objects
You can create MD5 objects, update them, and convert them to hex and base64 values.
Create a new MD5 object
var _md5 = crypto.getMD5();
Update an MD5 object
Syntax
_md5.update(value);
Parameters
- value - (String) Any string value.
Example
Update an MD5 object:
_md5.update("salt_value"); _md5.update("some text");
Return the MD5 object as a hex string
var _hashed_token = _md5.digest();
Return the MD5 object as a base64 string
var _hashed_token = _md5.digest64();
Crypto date/time support
The crypto object supports date/time formatting patterns.
crypto.dateFormat()
Returns a date in string format.
Syntax
crypto.dateFormat(format, [timezone], [time])
Parameters
- format - (String) The underlying implementation for this parameter is java.text.SimpleDateFormat. For example: 'YYYY-MM-DD HH:mm:ss.SSS'
- timezone - (String, optional) The underlying implementation for this parameter is java.util.TimeZone. This parameter is the sameDefault: UTC
- time - (Number, optional) A Unix timestamp value to format. Default: current time
Examples
Get the current time, down to milliseconds:
var _now = crypto.dateFormat('YYYY-MM-DD HH:mm:ss.SSS');
Get the current time for the Pacific Time Zone:
var _pst = crypto.dateFormat('YYYY-MM-DD HH:mm:ss.SSS','PST');
Get the value of ten seconds from now:
var _timeNow = Number(context.getVariable('system.timestamp')); var tenSeconds = crypto.dateFormat('YYYY-MM-DD HH:mm:ss.SSS','PST', _timeNow + 10 * 1000);
Additional examples. See also the java.text.SimpleDateFormat documentation.
var _pst = crypto.dateFormat('M');
var _pst = crypto.dateFormat('EEE, d MMM yyyy HH:mm:ss Z');
var _pst = crypto.dateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
Use getHash() to get any of the supported hash objects
Examples
var _hash1 = crypto.getHash('MD5'); var _hash2 = crypto.getHash('SHA-1'); var _hash3 = crypto.getHash('SHA-256'); var _hash4 = crypto.getHash('SHA-512');
Sample with crypto
try { // get values to use with hash functions var salt = context.getVariable("salt") || 'SomeHardCodedSalt'; var host = context.getVariable("request.header.Host"); var unhashedToken = ""; var _timeNow = Number(context.getVariable('system.timestamp')); var now = crypto.dateFormat('YYYY-MM-DD HH:mm:ss.SSS','PST', _timeNow); unhashed_token = "|" + now + "|" + host // generate a hash with the unhashedToken: var sha512 = crypto.getSHA512(); sha512.update(salt); sha512.update(unhashedToken); // convert to base64 var base64Token = sha512.digest64(); // set headers context.setVariable("request.header.now", now); context.setVariable("request.header.token", base64Token); } catch(e) { throw 'Error in Javascript'; }
context object reference
A context
object is created for each request/response transaction executed by an
API proxy. The context
object exposes methods to get, set, and remove variables
related to each transaction.
Variables define properties specific to a transaction. The time of day, the locale of the
requesting client, the user-agent of the requesting client, and the URL of the target service are
all examples of variables that are available in the context
. Therefore,
context
is useful for building logic that relies on these properties to execute
custom behavior.
See Flow variables reference and ExtractVariables policy.
context object summary
This table briefly describes the context object and its children, and lists the properties that are bound to each.
Name | Description | Properties |
---|---|---|
context |
A wrapper for the message processing pipeline context and the request and response Flows that are executed by the ProxyEndpoint and TargetEndpoint. | flow, session |
context. proxyRequest |
An object that represents the inbound request message to the ProxyEndpoint (from the requesting app to the API proxy) | headers, query parameters, method, body, url |
context. targetRequest |
An object that represents the outbound request message from the TargetEndpoint (from the API proxy to the backend service). | headers, query parameters, method, body, url |
context. targetResponse |
An object that represents the inbound target response message (from the backend service to the API proxy) | headers, content, status |
context. proxyResponse |
An object that represents the outbound proxy response message (from the API proxy to the requesting app) | headers, content, status |
context.flow |
The name of the current flow. | See context.flow. |
context.session |
A map of name/value pairs that you can use to pass objects between two different steps
executing in the same context. For example: context.session['key'] = 123 . |
For more information on when and when not to use this object, see What is the difference between context.session['hello'] = {} and context.setVariable("hello", {}). |
context object methods
context.getVariable()
Retrieves the value of a pre-defined or custom variable.
Syntax
context.getVariable("variable-name");
Example
To get the value for the current year:
var year = context.getVariable('system.time.year');
context.setVariable()
Sets the value for a custom variable or for any writable pre-defined variables.
Syntax
context.setVariable("variable-name", value);
Example
A common scenario for setting a variable is when an API proxy must dynamically write the
target URL. The following JavaScript obtains the value of a variable called USER.name, appends that value as a query parameter to the URL
http://mocktarget.apigee.net?user=
, and then sets the pre-defined
target.url
to that value.
context.setVariable("target.url", "http://mocktarget.apigee.net/user?user="+context.getVariable("USER.name"));
context.removeVariable()
Removes a variable from the context.
Syntax
context.removeVariable('variable-name');
context object properties
The flow
property is a string that identifies the current API proxy flow. This
property is used to indicate the Flow to which the JavaScript is attached. Supported values
are:
PROXY_REQ_FLOW
PROXY_RESP_FLOW
TARGET_REQ_FLOW
TARGET_RESP_FLOW
Each Flow name encompasses the PreFlow, PostFlow, and any conditional Flows defined in the ProxyEndpoint(s) or TargetEndpoint(s).
This optional property is useful when common JavaScript is executed in more than one Flow, but might vary its behavior depending on the Flow in which it executes. Use the Flow property for JavaScript modules intended to be reused in multiple API proxies, in which the code is required to check the current Flow before executing logic.
Example
Set an HTTP header only on the targetRequest Flow:
if (context.flow=="TARGET_REQ_FLOW") { context.targetRequest.headers['TARGET-HEADER-X']='foo'; }
Set the content only on the proxyResponse Flow:
if (context.flow=="PROXY_RESP_FLOW") { context.proxyResponse.content='bar'; }
A map of name/value pairs that can be used to pass objects between two policies executing within the same message context.
Example
Set a value in the session:
context.session['key'] = 123;
Get the value from the session:
var value = context.session['key']; // 123
context object children
As shown below, a complete API proxy Flow encompasses four distinct phases, each of which has an associated message object that is a child of the context object:
context.proxyRequest
: The inbound request message received from the requesting client.context.targetRequest
: The outbound request message sent to the backend service.context.proxyResponse
: The outbound response message returned to the requesting client.context.targetResponse
: The inbound request message received from the backend service.
The following sections describe the methods and properties of these objects:
context.*Request child objects
For each HTTP transaction that executes in an API proxy, two request message objects are created: one inbound (the request from the client) and one outbound (the request generated by the API proxy and submitted to the backend target.)
The context
object has child objects that represent these request messages:
context.proxyRequest
and context.targetRequest
. These objects let you
access properties within the request flow that is in scope when your JavaScript code
executes.
context.*Request child object properties
Property name | Description |
---|---|
url |
The The complete URL of the request is composed of the following properties:
When getting
|
Examples: context.targetRequest.url = 'http://www.example.com/path?q1=1' context.targetRequest.protocol ='https'; |
|
headers |
HTTP request headers as a mapping of |
Examples: For this HTTP request: POST /v1/blogs HTTP/1.1 Host: api.example.com Content-Type: application/json Authorization: Bearer ylSkZIjbdWybfs4fUQe9BqP0LH5Z context.proxyRequest.headers['Content-Type']; context.proxyRequest.headers['Authorization']; will return the following values application/json Bearer ylSkZIjbdWybfs4fUQe9BqP0LH5Z |
|
queryParams |
The request message query parameters as a mapping of |
Examples: "?city=PaloAlto&city=NewYork" can be accessed as: context.proxyRequest.queryParams['city']; // == 'PaloAlto' context.proxyRequest.queryParams['city'][0] // == 'PaloAlto' context.proxyRequest.queryParams['city'][1]; // == 'NewYork' context.proxyRequest.queryParams['city'].length(); // == 2 |
|
method |
The HTTP verb (GET, POST, PUT, DELETE. PATCH, etc.) associated with the request |
Examples: For this request: POST /v1/blogs HTTP/1.1 Host: api.example.com Content-Type: application/json Authorization: Bearer ylSkZIjbdWybfs4fUQe9BqP0LH5Z The following JavaScript: context.proxyRequest.method; will return the following value POST |
|
body |
The message body (payload) of the HTTP request. The request body has the following members:
|
Examples: For an XML body: <customer number='1'> <name>Fred<name/> <customer/> To access the elements of the XML object as follows: var name = context.targetRequest.body.asXML.name; To access XML attributes, use the var number = context.targetRequest.body.asXML.@number; For a JSON request body: { "a": 1 , "b" : "2" } var a = context.proxyRequest.body.asJSON.a; // == 1 var b = context.proxyRequest.body.asJSON.b; // == 2 To read form parameters: "vehicle=Car&vehicle=Truck" v0 = context.proxyRequest.body.asForm['vehicle'][0]; v1 = context.proxyRequest.body.asForm['vehicle'][1]; |
context.*Response child objects
For each HTTP transaction the executes in an API proxy, two response message objects are created: one inbound (the response from the backend service) and one outbound (the response sent back to the client.)
The context object has child objects that represent these response messages:
context.proxyResponse
and context.targetResponse
. These objects let you
access properties within the response flow that is in scope when your JavaScript code
executes.
context.*Response object properties
Property name | Description |
---|---|
headers |
The HTTP headers of the response message as a mapping of |
Example: var cookie = context.targetResponse.headers['Set-Cookie']; |
|
status |
The status code with status message as a property. Both status code and status message are available as properties. |
Example: var status = context.targetResponse.status.code; // 200 var msg = context.targetResponse.status.message; // "OK" |
|
content |
The HTTP body (payload content) of the response message. Response content has the following members: context.targetResponse.content.asXML; context.targetResponse.content.asJSON; |
Using .asXML notation
There is a handy way to walk through an XML document using the .asXML
notation.
This section describes how to use this notation, and how it differs from
request.content
and context.proxyRequest.content
.
For example:
request.content.asXML
or
context.proxyRequest.content.asXML
Both the *.content
and *.content.asXML
forms can be used in a string
context, and JavaScript will coerce them to become strings. In the former case
(*.content
), the string includes all declarations as well as XML comments. In the
latter case (*.content.asXML
), the string value of the result is cleaned of
declarations and comments.
Example
msg.content:
<?xml version="1.0" encoding="UTF-8"?> <yahoo:error xmlns:yahoo="http://yahooapis.com/v1/base.rng" xml:lang="en-US"> <yahoo:description>Please provide valid credentials. OAuth oauth_problem="unable_to_determine_oauth_type", realm="yahooapis.com" </yahoo:description> </yahoo:error> <!-- mg023.mail.gq1.yahoo.com uncompressed/chunked Sat Dec 14 01:23:35 UTC 2013 -->
msg.content.asXML:
<?xml version="1.0" encoding="UTF-8"?> <yahoo:error xmlns:yahoo="http://yahooapis.com/v1/base.rng" xml:lang="en-US"> <yahoo:description>Please provide valid credentials. OAuth oauth_problem="unable_to_determine_oauth_type", realm="yahooapis.com" </yahoo:description> </yahoo:error>
Furthermore, you can use the .asXML
form to traverse the XML hierarchy, by
specifying the names of elements and attributes. It is not possible to traverse the hierarchy
using the other syntax.
Debug with JavaScript print() statements
If you're using the JavaScript policy to execute custom JavaScript code, note that you can use the print() function to output debug information to the Debug tool. This function is available directly through the JavaScript object model. For example:
if (context.flow=="PROXY_REQ_FLOW") { print("In proxy request flow"); var username = context.getVariable("request.queryparam.user"); print("Got query param: " + username); context.setVariable("USER.name", username); print("Set query param: " + context.getVariable("USER.name")); } if (context.flow=="TARGET_REQ_FLOW") { print("In target request flow"); var username = context.getVariable("USER.name"); var url = "http://mocktarget.apigee.net/user?" context.setVariable("target.url", url + "user=" + username); print("Callout to URL: ", context.getVariable("target.url")); }
To see the output, select Output from all transactions at the bottom of the
Debug window. You can also find output in the Debug property called stepExecution-stdout
.
Making JavaScript callouts with httpClient
Use httpClient
to make multiple, parallel, asynchronous HTTP requests to any URL
from within custom JavaScript code executing in an API proxy flow.
The httpClient
object is exposed by the Apigee Javascript object
model.
About httpClient
The httpClient
object is exposed to custom JavaScript code running on Apigee
through the JavaScript object model. To attach custom JavaScript to an API proxy, you use the
JavaScript policy. When the
policy runs, the custom JavaScript code executes.
The httpClient
object is useful for developing composite services or
mashups. For example, you can consolidate multiple backend calls into a single API method.
Here's a basic usage pattern. Instantiate a Request object, assign to it a URL (e.g., to a
backend service you wish to call), and call httpClient.send
with that request
object.
var myRequest = new Request(); myRequest.url = "http://www.example.com"; var exchangeObj = httpClient.send(myRequest);
httpClient Reference
The HTTP Client exposes two methods: get()
and send()
.
httpClient.get()
A convenience method for simple HTTP GET
requests, with no support for HTTP headers.
Usage
var exchangeObj = httpClient.get(url);
Returns
The method returns an exchange
object. This object has no properties, and it
exposes the following methods:
isError()
: (Boolean) Returnstrue
if the httpClient was unable to connect to the server. HTTP status codes4xx
and5xx
result inisError()
false
, as the connection completed and a valid response code was returned. IfisError()
returnstrue
, then a call togetResponse()
returns the JavaScriptundefined
.isSuccess()
: (Boolean) Returnstrue
if the send was complete and successful.isComplete()
: (Boolean) Returnstrue
if the request is complete.waitForComplete()
: Pauses the thread until the request is complete (by success or error).getResponse()
: (object) Returns the response object if thehttpClient.send()
was complete and successful. The returned object has the identical methods and properties as the context.proxyResponse object. See context object summary.getError()
: (string) If the call tohttpClient.send()
resulted in an error, returns the error message as a string.
Example
Send a fully configured Request object containing the properties of the HTTP request. Use a non-blocking callback to process the response.
// Add the required the headers for making a specific API request var headers = {'X-SOME-HEADER' : 'some value' }; // Make a GET API request along with headers var myRequest = new Request("http://www.example.com","GET",headers); // Define the callback function and process the response from the GET API request function onComplete(response,error) { // Check if the HTTP request was successful if (response) { context.setVariable('example.status', response.status); } else { context.setVariable('example.error', 'Woops: ' + error); } } // Specify the callback Function as an argument httpClient.get(myRequest, onComplete);
Using the JavaScript policy
Use the JavaScript policy to attach custom JavaScript code to a proxy flow. See JavaScript policy.