The Largest Repository of ColdFusion Knowledge in The World for More Than 12 Years

ColdFusion on Ulitzer

Subscribe to ColdFusion on Ulitzer: eMailAlertsEmail Alerts newslettersWeekly Newsletters
Get ColdFusion on Ulitzer: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


CFDJ Authors: AppDynamics Blog, Michael Kopp, Tad Anderson, Bob Gourley, Jayaram Krishnaswamy

Related Topics: RIA Developer's Journal, ColdFusion on Ulitzer, Apache Web Server Journal, SOA & WOA Magazine, PHP Developer's Journal

RIA & Ajax: Article

AJAX in a SOA

A service-oriented architecture isn't much more than a loosely coupled collection of services - often Web services

This content is reprinted from Real-World AJAX: Secrets of the Masters published by SYS-CON Books. To order the entire book now along with companion DVDs for the special pre-order price, click here for more information. Aimed at everyone from enterprise developers to self-taught scripters, Real-World AJAX: Secrets of the Masters is the perfect book for anyone who wants to start developing AJAX applications.

AJAX in a Service-Oriented Architecture
A service-oriented architecture isn't much more than a loosely coupled collection of services - often Web services. Services are defined as a unit of work done by a service provider for a service consumer. One of the ways that SOA achieves that loose coupling is by remaining independent of a given technology (such as PHP or ColdFusion) and hiding the details of the implementation - much like a Web service.

Figure 6.8 illustrates a very basic SOA. The Service Consumer makes a request to the Service Provider and the Service Provider sends a response. Since the response is often in XML, AJAX is a nearly ideal tool for designing a lightweight browser-based client for a SOA. AJAX provides a dynamic interface that can provide an experience reminiscent of a desktop application at a fraction of the cost and significantly less hardware.

Concerns over Web service security and the lack of a formal definition for both SOA and AJAX are two of the hurdles that must be overcome before we'll see widespread adoption of AJAX in SOAs. Luckily OASIS, the Organization for the Advancement of Structured Information Standards, has formed a technical committee to develop a reference model for SOA. According to OASIS this is to help eliminate the ambiguous, differing, or conflicting use of the term in an increasing number of contexts. Its hope is that the reference model will encourage the growth of SOA while providing a baseline definition for SOA.

Version 1.0 of the draft RM for SOA is available for download at www.oasis-open.org/committees/download.php/16587/wd-soa-rm-cd1ED.pdf.

In addition to not having a formal reference model, AJAX also lacks robust server-side frameworks that help to produce a platform- and browser-agnostic application that will seamlessly integrate with existing services. That stale CRM application or DOS-based point-of-sale system can be replaced with a Web browser and will run faster and with more features on the same hardware as its predecessor.

That's not to say that AJAX isn't ready for the SOA. In fact, it's likely to drive the growth of SOA architecture as development moves from the desktop application to the browser running on a computer, a PDA, a cell phone, and possibly even other devices like your cable box or DVR.

Cross-Domain Issues
Many modern Web sites share their data via a simple POX Web service interface. Examples include Amazon product information, photo feeds from Flickr, music metadata from Last.fm, and so on. Since accessing these APIs is usually just a case of sending an HTTP message and getting an XML response back, an AJAX application seems to have all the tools it needs to access third-party services directly. However, as you learned before, there's a catch.

Listing 6.14 shows a simple AJAX request to the Yahoo! Maps geocoding API. If you pass a zip code to the geocoding service, it will return geographical information about the location it represents.

Listing 6.14

lookupZip = function(zip) {

     var baseurl = "http://api.local.yahoo.com/MapsService/V1/geocode";

     var params = [
         "appid=realworldajax",
         "zip="+zip
       ];

     var url = baseurl + "?" + params.join("&");

     // Use Prototype to obtain XMLHttpRequest instance
     var req = Ajax.getTransport();

     try {
       req.onreadystatechange=function() {
         if ((req.readyState==4)) {
           if (req.status==200) {
             showResponse(req);
           } else {
             showError(req);
           }
         }
       }
       req.open("GET",url,true);
       req.send(null);
     } catch (ex) {
       alert(ex);
     }
}

The first thing that this function does is take the Yahoo! geocoding URL and append two parameters. One is the zip code supplied by the application's user, and the other is a unique ID that allows Yahoo! to limit the number of requests made to its service from a particular application. If you want to experiment with this code, you should get your own Application ID from http://api.search.yahoo.com/webservices/register_application.

Once the complete request URL is formed, the function dispatches an AJAX request to it. This section of code is wrapped in a try/catch block, meaning that any JavaScript exceptions that occur in the try section will be trapped and handled by the catch.

Figure 6.9 shows what happens when this code runs.

No, there's nothing wrong with the code - this dialog (and similar ones you'll see in other browsers) is the result of security features built into the browser.

To prevent malicious Web pages from surreptitiously capturing users' private data, browser vendors have adopted the convention that a Web page can only use AJAX requests to communicate to the same domain that the page's JavaScript itself was served from (called the "originating domain"). So even if evil hackers were able to capture your password by injecting malicious code into your online bank's login page at bigcorporatebank.com/login.html, they'd only be able to send the stolen password back to another URL in the bigcorporatebank.com domain. If they attempted to use AJAX to send data back to their own domain at weareevilhackers.com, the browser security restrictions would foil them.

In the geocoding example, the Web page was served from my development server at http://buttercup/. This means that I can only use AJAX to make requests to other resources that reside in the buttercup domain, so the request to yahoo.com isn't allowed.

Fortunately, there's a workaround: cross-domain proxying. In a nutshell, this means that you send your AJAX request to the server that originated the Web page, which passes your request to the thirdparty server you really want to talk to. The third-party server generates a response to your query, which is returned to the originating server and is then passed straight back through to the browser.

Cross-Domain Proxying

Figure 6.10 illustrates how AJAX requests from a browser to a third-party server are prevented by browser security constraints. Instead, the Web page's originating server can be used to proxy the browser's request to a third-party domain and return its response.

There are many ways to proxy requests between domains. For example, you could write a Java servlet or a PHP script to open a stream to a remote server and output its response back to the browser. However, many popular Web servers have proxying functionality built in, and it's sensible to use this capability when it's available. Here we're going to show you how to use the Apache Web server to proxy calls to a third-party server.

Proxying with Apache mod_rewrite
First of all, you have to ensure that your Apache server has the modules mod_proxy and mod_rewrite available. These modules are commonplace, but are often disabled by default. The Apache documentation will be helpful if you're not sure how to enable them. Next, you have to create an .htaccess configuration file in the directory where your AJAX application lives, which will define the settings for the cross-domain proxy. In our case, that directory is ~phil/public_html/rwa-samples.

Here's how we're configured Apache to proxy requests to Yahoo!: RewriteRule ^proxy$ http://api. local.yahoo.com/MapsService/V1/geocode?appid=realworldajax [P,QSA]

The first line simply enables the mod_rewrite functionality for requests that are made to this location on the server. There are several things happening in the next line, so I'll break it down and examine each part in turn.

  • RewriteRule: This defines a URL processing rule.
  • ^proxy$: This is a regular expression that is applied to each request. If the request URL matches this regular expression, then the RewriteRule is applied to it, otherwise the request is passed through unchanged. The regular expression is applied relative to the location of the .htaccess file, i.e., relative to http://buttercup/~phil/rwa-samples/. Here, the only URL that matches the rule is http://buttercup/~phil/rwa-samples/proxy. Note that the query string is not considered a part of the URL here. RewriteRule only looks at the path.
  • http://api.local.yahoo.com/MapsService/V1/geocode?appid=realworldajax: If a request matches the rule's regular expression, it should be redirected to this location. Note that using a proxy like this lets you hide parts of the query that you don't want curious end users to discover. In this case I'm concealing the application ID by adding it to the URL server side.
  • [P,QSA]: These switches tell Apache how the request redirection should be performed. "P" means that Apache should proxy the request to the remote host, as opposed to simply redirecting the browser with a 302 response code. QSA stands for "Query String Append," and tells Apache to add the original request's query parameters to the proxied request. This means that the appid parameter in the redirection URL will be combined with the zip code parameter sent from the AJAX client.
At this point, it's a good idea to test the proxying in isolation. A quick way for me to do this is simply to point my Web browser at http://buttercup/~phil/rwa-samples/proxy.

In Figure 6-11, the server returns an XML error message from the Yahoo! Web service, confirming that the proxy is working. With the proxy in place, we can now alter the JavaScript code that performs the zip code lookup:

Listing 6.15

lookupZip = function(zip) {

     var baseurl = "http://buttercup/~phil/rwa-samples/proxy";

     var params = [
           "zip="+zip
         ];

     var url = baseurl + "?" + params.join("&");

     // Use Prototype to obtain XMLHttpRequest instance
     var req = Ajax.getTransport();

     try {

       req.onreadystatechange=function() {
         if ((req.readyState==4)) {
           if (req.status==200) {
             showResponse(req);
           } else {
             showError(req);
           }
         }
      }

       req.open("GET",url,true);
       req.send(null);

     } catch (ex) {
       alert(ex);
     }
}

The request URL has been altered to point to the proxy path on the originating server. The application ID is also no longer needed in the params array, since it's now added to the query as part of the proxying process.

We can now use the AJAX-based form to do the zip code lookup correctly, displaying the city and longitude/latitude of the zip code on the page.

The lower portion of Figure 6.12 shows the FireBug extension for Firefox. One of FireBug's many abilities is capturing AJAX calls made from a Web page. Here you can see the actual request URL that's dispatched by the lookupZip() function and a portion of the XML response from the Yahoo! geocoding Web service.

Cross-Domain Proxying Summary
If you want to get data using AJAX calls to a third-party Web API, a proxy is needed to satisfy the browser security constraints, since AJAX requests can only be made to the domain that originated the current page. Setting up a simple Apache proxy using mod_rewrite only takes a couple of lines of configuration. Not only is it completely transparent to the client, it can also be used to prevent special parameters such as API keys and passwords from being exposed in client code.

This content is reprinted from Real-World AJAX: Secrets of the Masters published by SYS-CON Books. To order the entire book now along with companion DVDs, click here to order.

More Stories By Corey Gilmore

Corey Gilmore is the president of CFG Consulting, Inc., specializing in developing rich internet applications with ColdFusion, PHP and Ajax for the Federal government and Fortune 100 clients. He guiltily enjoys designing and implementing low-cost, high performance business continuity plans using VMware ESX server. As the former Director of Information Technology for the United States Senate Democratic Leadership, he designed and implemented a continuity of operations plan to ensure Senate business continuity in the event of a disaster. Corey can be reached at cfgci.com.

More Stories By Jason Blum

Jason Blum is principal engineer with the advanced technologies development team in the United States Senate, Office of the Sergeant at Arms. Formerly the lead administrator of the Senate’s shared Web hosting environment, Jason now designs and manages the implementation of schema and pattern-centric solutions for Senate offices in XML, ColdFusion, Flex, and .NET. He is a Certified Advanced ColdFusion developer with a BA in philosophy, Masters Degrees in philosophy of education and in IT, and an intermediate certification in Hungarian from itk.hu.

More Stories By Phil McCarthy

Philip McCarthy is a UK-based software development consultant
specializing in J2EE and Web technologies. An early adopter of rich
browser-based client development, he has several years' experience of integrating Ajax technologies into enterprise Java frameworks, gained on projects in the financial services, telecoms, and digital media sectors. Philip is also the author of the "Ajax for Java Developers" series for IBM developerWorks, and blogs about software development at chimpen.com.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.