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
- protocol: The protocol of the URL (for example, HTTP, HTTPS)
- host: The host of the URL (for example, www.example.com)
- port: The port (for example, :80, :443)
- 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() && ex2.isSuccess() {
response.content = ex1.getResponse().content +
ex2.getResponse().content
}