RESTful web services and jQuery make it easy to create an enterprise mashup. This 2 part article discusses how to create a simple enterprise mashup using jQuery. Part 1 introduced the basic requirements of your enterprise services, the simplicity of JSON, and how to consume your RESTful web services using jQuery. Part 2 covers consuming services from across the enterprise with JSONP, accessing secure resources, and handling error conditions.

Gathering data from across the enterprise

A mashup generally retrieves data from services throughout the enterprise. You may recall form part 1 that our RESTful web service was located at: http://solutionsfit.com/services/rest/consultants. So where is our mashup located? If it is located in a different domain than solutionsfit.com, say: mycorpdomain.net, the browser will enforce the same-origin policy browser restriction and disallow access.

This restriction can be bypassed through use of JSONP (JSON with padding). For more information on what JSONP is and how to support JSONP within your web services, see my previous posting: Serving up JSONP from your JAX-RS Web Services.

By adding the callback=? parameter to our getJSON invocation in Part 1 we inform jQuery to use JSONP. The parameter is simply added to the URL we are requesting:

jQuery.getJSON(
  'http://solutionsfit.com/services/rest/consultants&callback=?',
  function(data) {
    // ... ...
  }

When jQuery recognizes that a JSONP request is being performed, it takes the function we defined, assigns a unique name, and adds it as a global function. It then replaces the question mark in the callback=? parameter with the name it assigned. This allows the service to wrap the JSON result with the callback function to invoke.

If the service to return our consultants supported JSONP, and jQuery requests: http://solutionsfit.com/services/rest/consultants?callback=jquery12345, the following result would be returned.

jquery12345([{
 "consultant" : {
   "firstName": "Jacob",
   "lastName": "Orshalick",
   "blogFeed": "http://solutionsfit.com/blog/feed"
 },
{
 "consultant": {
   "firstName": "Nirav",
   "lastName": "Assar",
   "blogFeed": "http://assarconsulting.blogspot.com/feeds/posts/default"
 }
}]);

As you can see, the JSON result is wrapped with the callback function jquery12345. Because jQuery adds this function as a global function, it will be called when the service result is evaluated. As a final step, jQuery removes that function once the callback completes.

Accessing secure enterprise web services

So far we have assumed that our services provide wide open access, but most internal enterprise services require authentication. In addition, it is often necessary to restrict what data is returned to a user based on roles and permissions. While this may seem complex, intranet access can provide a unique advantage when using jQuery to create an enterprise mashup.

Intranet environments often provide single-sign on mechanisms that are not available through external service invocations. Given the HTTP-centric approach of REST, the most natural fit for RESTful web service authentication is HTTP authentication. While the specification only provides for BASIC and DIGEST authentication, almost all current browsers support the much more secure HTTP Negotiate mechanism.

The HTTP Negotiate mechanism is the most common use of SPNEGO which allows a client and server to negotiate an authentication mechanism. Many enterprise intranet domains, especially those using Active Directory for authentication, utilize the HTTP Negotiate mechanism (e.g. NTLM or Kerberos) to achieve single-sign on behavior. By securing RESTful web services through the HTTP Negotiate mechanism, and using jQuery to invoke the service, we can rely on the browser’s built in HTTP Negotiate capabilities to authenticate the user.

Let’s say that our previous RESTful web service now required authentication through the HTTP Negotiate mechanism. Now when the URL is requested http://solutionsfit.com/services/rest/consultants, an HTTP 401 Unauthorized response is sent with the following header entry.

WWW-Authenticate: Negotiate

If the browser is accessing a trusted domain it will attempt to authenticate silently through the Negotiate mechanism (either NTLM or Kerberos). As you would expect, this is the same behavior we would see from accessing a general web application protected by the HTTP Negotiate mechanism.

When the jQuery getJSON request is performed, the AJAX invocation receives the same response. As with the previous case, the browser will silently negotiate user authentication and receive the expected JSON result. No additional code is necessary as long as we are accessing a trusted domain and a service supporting the HTTP Negotiate mechanism. The service will silently authenticate the user and provide the appropriate JSON result according to the user’s privileges.

As a JBoss user, I recommend JBoss Negotiation for securing RESTful services through the HTTP Negotiate mechanism. JBoss Negotiation provides a Tomcat authenticator and JAAS login module to add SPNEGO support to JBoss.

Handling failure conditions

So we’ve discussed what happens if things go right, but what if things go wrong? What if the service is down or we can’t authenticate? We need to be able to inform the user that a failure occurred. The current implementation of the jQuery getJSON function does not handle error conditions when using a JSONP request. The call fails silently and any defined error function is ignored.

A simple approach to handle error conditions in a generic way is a timeout. The following implementation demonstrates how a timeout could be applied to our getJSON call in Part 1.

var requestCompleted = false;

window.setTimeout(function() {
  if(!requestedCompleted) {
    jQuery("#consultants")
      .append('<tr><td style="color: red">' +
        'An error occurred while processing this request' +
        '</td></tr>');
  }
}, 5000);

jQuery.getJSON(
  'http://solutionsfit.com/services/rest/consultants&callback=?',
  function(data) {
    requestCompleted = true;

    jQuery.each(data, function(i,item) {
      var consultant = item.consultant;
      var consultantHtml = '<tr>' +
        '<td>' + consultant.firstName + ' '
          + consultant.lastName + '</td>' +
        '<td><a href="' + consultant.blogFeed + '">' +
          'Blog Feed</a></td>' +
        '</tr>';

      jQuery("#consultants").append(consultantHtml);
    });
  }
);

The timeout above is set to 5 seconds, but should be set according to an expected response time for your service. The window.setTimeout function will invoke our defined error handling function after a 5 second period. Unless the request completes within that period and invokes our callback function, the following message will be displayed to the user.

An error occurred while processing this request

While this may be a reasonable approach, there are certainly drawbacks. First, we don’t know what error occurred, simply that the request timed out. If the request fails due to an authentication issue for example, we would likely want to inform the user so they could get the issue resolved. Second, if we set our timeout period too low, we could error out on requests that actually complete. Fortunately, if these issues are of concern, there is an alternative.

The jQuery JSONP project in GoogleCode provides support for error handling. While the usage is not as elegant as the standard getJSON function, it does provide the necessary features to handle these concerns. This StackOvervflow entry provides an example of usage.

Conclusion

As you have seen in this 2 part series, jQuery simplifies enterprise mashup development with RESTful web services. jQuery provides a clean approach to retrieving and rendering service data, bypasses the same-origin policy browser restriction through JSONP support, and allows you to take advantage of HTTP authentication. Hopefully better error handling will be incorporated into JSONP support in future jQuery revisions, but as you have seen, there are ways to get around this issue.