Was this helpful?

In this cookbook example, you will learn how to create a mashup by attaching a JavaScript HTTP client to a proxy. This useful pattern lets you combine results from multiple backend targets using JavaScript to process requests and responses.

For a general overview of the HTTP client pattern, see "The JavaScript HTTP client pattern" in API Proxy Cookbook patterns

Download and try out the sample code

We recommend that you download and try out this topic's sample code. The sample is called javascript-mashup-cookbook, which you can find in the doc-samples folder in the Apigee Edge API Services samples repository in GitHub. For information on downloading Apigee samples, see Using the samples

Instructions for deploying and calling this cookbook sample API are provided in the README file that comes with the sample. You can also find brief deployment instructions here: Deploying and testing samples.

About this cookbook example

This cookbook example illustrates an API proxy pattern that uses a JavaScript HTTP client object to call multiple backend services directly. As you will see, the JavaScript HTTP client code is attached as a policy to the ProxyEndpoint. In this case, the pattern does not require a TargetEndpoint; the HTTP client handles all communication with the backend targets. For a general overview of this pattern and other related ones, see API Proxy Cookbook patterns.

When using this mashup API, app developers may be unaware of where the backend data comes from. All an app developer knows about is how to call your proxy. The details of how the data is retrieved and mashed up are not necessarily exposed.

The example discussed here uses a custom HTTP client written in JavaScript to mash up data from these two separate public APIs:

  • The Google Geocoding API: This API converts addresses (like "1600 Amphitheatre Parkway, Mountain View, CA") into geographic coordinates (like latitude 37.423021 and longitude -122.083739).
     
  • The Google Elevation APIThis API provides a simple interface to query locations on the earth for elevation data. In this example, the coordinates returned from the Geocoding API will be used as input into this API. This is a typical pattern where APIs are chained together using proxies.

 

The API surfaced through this proxy to app developers takes two query parameters: a postal code and a country ID. An app developer calls this proxy API like this:

$ curl "http://{myorg}-test.apigee.net/javascript-mashup-cookbook?country=us&postalcode=80503"

The response is a JSON object that includes the geocoded location (latitude/longitude) for the center of the supplied postal code area combined with the elevation at that geocoded location. 

{"country":us,"postalcode":80503,"elevation":{"latitude":40.1724007,"longitude":-105.1960795},"altitude":{"meters":1570.249755859375,"feet":5151.7380519886965}}

Before you begin

If you'd like to read a brief overview of the HTTP client pattern illustrated in this cookbook topic, see "The JavaScript HTTP client pattern" in API Proxy Cookbook patterns.

Before you explore this cookbook example, you should also be familiar with these fundamental concepts:

  • What policies are and how to attach them to proxies. In this example, we build a single policy that wraps a JavaScript application. For a good introduction to policies, see Policy attachment and enforcement
     
  • The structure of an API proxy flow, as explained in Flow configurations. Flows let you specify the sequence in which policies are executed by an API proxy. In this example, a JavaScript policy is attached to the flow's ProxyEndpoint. 
     
  • How an API proxy project is organized on your filesystem, as explained in API proxy configuration reference. This cookbook topic demonstrates local development (file system-based) as opposed to cloud-based development where you could use the management UI to develop the API proxy.
     
  • As you will see, this example uses two out-of-the-box API platform components: variables and the Apigee JavaScript Object Model. If you'd like to review details about these components now, see Variables reference and JavaScript object model.
     
  • A working knowledge of JavaScript and XML.

If you have downloaded the sample code, you can locate all of the files discussed in this topic in the mashup-policy-cookbook sample folder. The following sections discuss the sample code in detail. 

Going with the flow

Before moving to the JavaScript code, let's take a look a the main flow of our example API proxy. The flow XML, shown below, tells us a lot about this API proxy, and how the JavaScript application is integrated into the flow. 

The important thing to notice about this API proxy is that the TargetEndpoint definition is not invoked by the RouteRule. In this case, the JavaScript application itself handles all of the mashup activities and populates the response object. No further processing in the API proxy "pipeline" is required. 

If you downloaded the sample from GitHub, you can find this API proxy definition in the file doc-samples/javascript-mashup-cookbook/apiproxy/proxies/default.xml.

<ProxyEndpoint name="default">
  <Flows>
    <Flow name="default">
      <Request/>
      <Response>
	<!-- Call the JavaScript that invokes both APIs and returns a response -->
	<Step><Name>MashItUp</Name></Step>
      </Response>
    </Flow>
  </Flows>

  <HTTPProxyConnection>
    <!-- Add a base path to the proxy to distinguish from others in the environment -->
    <BasePath>/javascript-mashup-cookbook</BasePath>
    <VirtualHost>default</VirtualHost>
  </HTTPProxyConnection>
  <RouteRule name="default">
    <!-- No route. The proxy will return the request and not call a backend service. -->
  </RouteRule>
</ProxyEndpoint>

Here's a summary of the flow's elements:

This is a ProxyEndpoint flow. The ProxyEndpoint configuration defines the inbound (app-facing) interface for an API proxy. When you configure a ProxyEndpoint, you define how apps invoke the proxied API.

  • <Request> - This API proxy does not use the <Request> element of the flow. In this pattern, the request is handled within the JavaScript application itself.
     
  • <Response> - The response part of the pipeline simply calls the JavaScript application, which handles the request from the client and all of the backend API calls. 
     
  • <HttpProxyConnection> - Specifies details about how apps will connect to this API proxy, including the <BasePath>, which specifies how this API will be called. 
     
  • <RouteRule> - The interesting thing about the <RouteRule> is that we don't specify one! That is, we don't specify a TargetEndpoint to invoke with <RouteRule>. With this pattern, there is no need to call the TargetEndpoint. The JavaScript application creates a response object that is returned to the client app. 

Coding the JavaScript application

Here's the complete listing of our example JavaScript application. For the most part, it is straightforward JavaScript, with some Apigee-specific objects and variables mixed in. For convenience, these objects and variables are shown in bold type in the code. We'll discuss the Apigee-specific parts and how the are made available to the application immediately following the code. 

// Initialize the response that might already be hanging around

response.content = '';
response.headers['Content-Type'] = 'application/json';

try {
   if ((request.queryParams.postalcode == undefined) ||
       (request.queryParams.country == undefined)) {
     throw '"postalcode" and "country" query parameters are required';
   }

   // Send an HTTP GET to the URL that we construct

   var geocoding = httpClient.get(
        'http://maps.googleapis.com/maps/api/geocode/json?address=' +
        request.queryParams.postalcode +
        '&region=' + request.queryParams.country +
        '&sensor=false');

    geocoding.waitForComplete();

    if (!geocoding.isSuccess()) {
        throw 'Error contacting geocoding web service';
    }

    // We got a response. Parse the JSON into a JavaScript object.

    geocodeResponse = geocoding.getResponse().content.asJSON;

    if (geocodeResponse.status != 'OK') {
        throw 'Error returned from geocoding web service: ' + geocodeResponse.status;
    }

    // Go through the JavaScript returned by Google and get the results

    var lat = geocodeResponse.results[0].geometry.location.lat;
    var lng = geocodeResponse.results[0].geometry.location.lng;

    // Send another HTTP GET to the other service

    var altitude = httpClient.get(
        'http://maps.googleapis.com/maps/api/elevation/json?sensor=false&locations=' +
            lat + ',' + lng);

    altitude.waitForComplete();

    if (!altitude.isSuccess()) {
        throw 'Error contacting altitude web service';
    }

    altitudeResponse = altitude.getResponse().content.asJSON;

    if (altitudeResponse.status != 'OK') {
        throw 'Error returned from altitude web service: ' + altitudeResponse.status;
    }

    var alt = altitudeResponse.results[0].elevation;    

    // Assemble the parts of the response as a JavaScript object

    var location = new Object();
    location.latitude = lat;
    location.longitude = lng;

    var altitude = new Object();
    altitude.meters = alt;
    altitude.feet = alt * 3.2808399;

    // Final assembly, then turn it into a JSON object

    var body = response.content.asJSON;
    body.country = request.queryParams.country;
    body.postalcode = request.queryParams.postalcode;
    body.elevation = location;
    body.altitude = altitude;

} catch (err) {

    // Handle any error that may have happened previously by generating a response
    response.content.asJSON.error = err;
}
As mentioned previously, this code includes Apigee-specific variables and objects. The variables are included through the API proxy runtime environment. They include request, response, request.queryParams, response.content, and response.headers. These variables are populated whenever an app submits a request to the API proxy. For more information about variables and how they participate in the API proxy environment, see Variables reference.
 
The other Apigee-specific object is httpClient (Apigee's JavaScript HTTP Client). This object is part of the Apigee JavaScript Object Model. This object model defines request, response, and context objects with associated properties. It's purpose in this example is to make requests to backend services (the Google APIs) and return responses from those services. As with variables, the HTTP client is made available out-of-the-box to JavaScript applications that are deployed in an API proxy. For more detailed information on httpClient, see JavaScript object model.

Creating the JavaScript policy

To work within the context of an API proxy, we need to wrap the JavaScript application in a policy. The proxy references this policy at the point of attachment and immediately executes the JavaScript. (If you wish, refer back to the section "Going with the flow" to see where this policy is attached to the flow.)

If you downloaded the sample from GitHub, you can find this policy in the file doc-samples/javascript-mashup-cookbook/apiproxy/policies/MashItUp.xml.

<JavaScript name="MashItUp" timeout="10000">
    <ResourceURL>jsc://MashItUp.js</ResourceURL>
</JavaScript>

Just a policy name and a reference to the JavaScript source file. Pretty simple.  

Testing the example

If you have not already done so, try to download, deploy, and run the javascript-mashup-cookbook sample, which you can find in the doc-samples folder in the Apigee Edge samples repository on GitHub. Just follow the instructions in the README file in the javascript-mashup-cookbook folder. Or, follow the brief instructions here: Deploying and testing samples.

To summarize, you can call the API as follows. Substitute your {myorg} with your organization name:

$ curl "http://{myorg}-test.apigee.net/javascript-mashup-cookbook?country=us&postalcode=80503"

The response is a JSON object that includes the geocoded location (latitude/longitude) for the center of the supplied postal code area combined with the elevation at that geocoded location. It also includes a conversion of the elevation from meters to feet. The data was retrieved from two backend APIs, mashed up inside the JavaScript application, massaged a bit, and returned to the client in a single response. 

{"country":us,"postalcode":80503,"elevation":{"latitude":40.1724007,"longitude":-105.1960795},"altitude":{"meters":1570.249755859375,"feet":5151.7380519886965}}

Summary

This cookbook topic explained how to attach an HTTP client written in JavaScript to an Apigee API proxy. One use for a pattern like this is to create a mashup of data pulled from multiple backend services. At the same time, because the JavaScript is attached to the API proxy as a policy, it can participate in Apigee Edge features like traffic management, security, mediation, and analytics.

Get help

For help, see Apigee Customer Support.

 

コメントを追加

Provide your email address if you wish to be contacted offline about your comment.
We will not display your email address as part of your comment.

We'd love your feedback and perspective! Please be as specific as possible.
Type the characters you see in this picture. (verify using audio)

Type the characters you see in the picture above; if you can't read them, submit the form and a new image will be generated. Not case sensitive.