Background

As an API developer you are undoubtedly familiar with Javascript. The Apigee API Platform enables you to leverage your background with Javascript to implement custom API behavior without having to change the code of your APIs or backend services.

Apigee's API Platform can be used as a managed container for executing your custom Javascript. You write the custom logic, and Apigee provides the container, security, management, monitoring, analytics.

The benefit of this approach is that it lets you offload common (uninteresting!) functions like rate limiting, API key provisioning, OAuth authorization, transformations, and such, freeing you to focus on innovation.

In short, you can combine Apigee's out-of-the-box policies with your own custom Javascript to implement sophisticated and reliable behavior that meets the needs of your apps and, if you expose APIs, your API developers.

The Apigee Object Model

If you have a good grasp of Javascript, you just need to become familiar with Apigee's object model. Javascript that executes in a browse  uses the browser object model, or BOM. Javascript that executes on the Apigee API Platform relies on a message-oriented object model. This object model defines request, response, and context objects with associated properties. This document describes these objects and provides samples to get you started writing your own Javascript against the Apigee object model.

Apigee's API Platform relies on Rhino, which is open-source implementation of JavaScript written in Java.

Apigee also uses E4X is an extension of JavaScript that adds support for XML.

When your Javascript is executed in an Apigee flow, a scope is created for the execution.

Three object references are created in the scope:

  • Request Object: A wrapper for the HTTP target request message
  • Response Object: A wrapper for the HTTP proxy response message
  • Context Object: A wrapper for the message context and flow

Request Object

The request object has a value of undefined before the Target Request PreFlow.

The request may be modified to redirect the request to a different target. Internally a Dynamic Target is created and attached to the context if the request is changed.

Request Object Properties

Request Headers: HTTP request headers as a mapping of String => List

Example:

request.headers['via'];  
request.headers['via'][1];

Request Query Parameters: The query params as a mapping of String => List

Example:

This query string:

"?city=PaloAlto&city=NewYork"

can be accessed as:

request.queryParams['city'];             // == 'PaloAlto'
request.queryParams['city'][0]           // == 'PaloAlto'
request.queryParams['city'][1];          // == 'NewYork' 
request.queryParams['city'].length();    // == 2  

Request Method: The HTTP verb associated with the request

"GET" |  "POST" | "PUT" | "DELETE"

Request Body: The body of the HTTP request

The request body has the following members:

request.body.asXML;   
request.body.asJSON; 
request.body.asForm;

Examples:

For an XML body:

"<customer number='1'><name>Fred<name/><customer/>"
var number = request.body.asXML.@number;
var name = request.body.asXML.name;

For a JSON request body:

"{ "a":1 , "b":2 }"
var a = request.body.asJSON.a;    // == 1
var b = request.body.asJSON.b;    // == 2

For body parameters:

"vehicle=Car&vehicle=Truck"
v0 = request.body.asForm['vehicle'][0]; 
v1 = request.body.asForm['vehicle'][1];

Request URL: The complete URI of the request

  1. protocol: The protocol of the URL (for example, HTTP, HTTPS)
  2. host: The host of the URL (for example, www.example.com)
  3. port: The port (for example, :80, :443)
  4. path: The path of the URI (for example, /v1/weather)

The URL is a convenience property that is a concatenation of:

protocol+port+host+path+queryParams

Example:

request.url = ‘http://www.example.com/path?q1=1
request.protocol =’https’;

results in

(request.url == ‘https://www.example.com/path?q1=1)

Response Object 

Response Headers: The response headers as a mapping of String => List

Example:

var date = response.headers['Date'];

Response Content: The body of the proxy response message.

Response content has the following members:

response.content.asXML;  
response.content.asJSON;

Examples:

For an XML response:

"<customer number='1'><name>Fred<name/><customer/>"
var number = response.content.asXML.@number;
var name = response.content.asXML.name;

For JSON response:

 "{ "a":1 , "b":2 }"
var a = response.content.asJSON.a;    // == 1
var b = response.content.asJSON.b;    // == 2

Response Status: The status code with status message as a property

Example:

var status = response.content.status;        // 200
var msg = response.content.status.message;   // "OK"

Context Object

Context Object Properties

Flow:The name of the current flow

The flow property exposes methods to get and remove variables.

getVariable(): Gets a variable

Example:

var year = context.getVariable(‘system.time.year’);

setVariable(): Sets a variable

removeVariable(): Removes a variable.

Session: A map of name/value pairs that can be used to pass objects between two steps executing within the same message context

Example:

context.session[‘key’]  = 123;
…
var value = context.session[‘key’];  // 123

Headers, Query Parameters, and Form Variables

Headers, Query Parameters and Form variables all share a common format: a name/value pair that maps one string to another string.

The format:

response.headers[‘foo’] = ‘bar’;

The name will always be a string, but the value may a string or list of strings.

If the value is a list, then the members of the list can be accessed by the array operator

response.headers[‘foo’][0] = ‘bar’;

in practice response.headers[‘foo’] is response.headers[‘foo’][0];

For example if the following headers are set in an HTTP response:

Content-Type: application/json
Via: 1.0 fred
Via: 1.1 example.com
response.headers[‘Content-Type’]       // “application/json”
response.headers[‘Content-Type’][0]   // “application/json”
response.headers[‘Content-Type’][1]   // undefined
response.headers[‘Via’]         // “1.0 fred”
response.headers[‘Via’][0]     // “1.0 fred”
response.headers[‘Via’][1]     // “1.1 example.com”

HTTP Client

The HTTP Client can be used to make multiple parallel, asynchronous HTTP requests to any URL.

The HTTP Client exposes two methods: get() and send().

get()

A convenience method for simple HTTP GETs, with no have any support for HTTP headers.

Example:

var exchange = httpClient.get(“http://www.example.com”);

send()

Enables full configuration of the request message using request object to contain the properties of the HTTP request.

The request object is identical in type to the request object generated by the standard Apigeee flow.

 var request = new Request();
  request.url = “http://www.example.com”;

  var exchange = httpClient.send(request); 

Alternatively:

  var headers = {‘X-SOME-HEADER’ : ‘some value’ };
  var request = new Request(“http://www.example.com”,”GET”,headers);
                var exchange = httpClient.send(request);

or

  var headers = {‘Content-Type : ‘application/xml’ };
  var request = new Request(“http://www.example.com”,”POST”,headers,”<foo/>”);
    var exchange = httpClient.send(request);

The calls to get() and send() immediately return an object that can used later to get the actual HTTP response, or to check if the response has timed out yet.

The returned object has the following methods:

  • isError()
  • isSuccess()
  • isComplete()
  • waitForComplete()
  • getResponse()
  • getError()

Example:

var ex1 = httpClient.get(“http://www.example.com?api1”); 
var ex2 = httpClient.get(“http://www.example.com?api2”);

The returned object can be accessed later during flow processing, for example by another Javascript policy:

ex1.waitForComplete();      // Thread is paused until the response is returned or error or step time limit has been reached.
ex2.waitForComplete(100);   // Thread is paused for a maximum of 100 ms.

if (ex1.isSuccess() &amp;&amp; ex2.isSuccess() {
 response.content = ex1.getResponse().content +
             ex2.getResponse().content
}