jQuery

Mobile in Minutes with Sinatra

Sinatra is described as a DSL for quickly creating web applications in Ruby with minimal effort. Sinatra makes it extremely easy to host a web application and expose RESTful services. Here we’ll show how this allows you to get mobile applications up and running in minutes with Sinatra.

Quick Introduction to Sinatra

The following ruby file is a valid RESTful service with Sinatra:

require 'sinatra'
require 'json/pure'

get '/hello/:name.json' do
  content_type :json
  {
    "message" => "Hello #{params[:name]}!"
  }.to_json
end

Here we are telling Sinatra to respond to any GET requests to the URI pattern /hello/.json. The inserted name is passed to the method as a parameter through the params hash. We set the returned content_type to JSON to ensure correct handling from the client and our hash is converted to a JSON response using json_pure.

To run this example, save the above code snippet to file named hello.rb. Then install and run your new application with Sinatra:

$ gem install json_pure
$ gem install sinatra
ruby -rubygems hello.rb

Now navigate to the URL http://localhost:4567/Jacob (feel free to use your own name) and you will be presented with:

{"message":"Hello Jacob!"}

Now we can easily consume that service with a jQuery script and host the script with Sinatra:

<html>
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script>
      $.getJSON('/hello/Jacob.json', function(data) {
        alert(data.message);
      });
    </script>
  </head>
  <body>
  </body>
</html>

Here we use jQuery’s getJSON method to retrieve the JSON data from our service. The message from the JSON result is then alerted to the user.

To run the example, create a folder named public in the same directory where you created your hello.rb file. Inside that folder copy the above code snippet into a file named hello.html. Now navigate to the following page in your browser http://localhost:4567/hello.html. You will be alerted with the message “Hello Jacob!”

Creating a Mobile App with Sinatra

That was easy enough, but let’s see how we can apply this to a mobile setting. For this example, let’s create and consume a Sinatra service using jQuery Mobile.

Downloading and Running the Example

The example can be downloaded in its entirety here. To run the example, unzip the downloaded file to a known directory and execute the following commands:

$ cd /unzipped/folder/directory
$ gem install json_pure
$ gem install sinatra
$ ruby -rubygems cameras.rb

Now navigate to the following page in your browser http://localhost:4567/cameras.html. You will see the list of cameras for selection.

Exposing the RESTful Service

Let’s first create our RESTful service which will provide a top 10 list of popular DSLR cameras:

require 'sinatra'
require 'json/pure'

get '/cameras/top10.json' do
  content_type :json
  [
    {
      'id' => 1,
      'title' => 'Canon Rebel T3 DSLR',
      'description' => '...',
      'price' => '499.99
    },
    {
      'id' => 2,
      'title' => 'Canon Rebel EOS DSLR',
      'description' => '...',
      'price' => '349.99'
    }
    # ... ...
  ].to_json
end

In this case we are just constructing a hash that we then return back to the client in the same manner as our previous example. We could also retrieve the list of cameras from a database call, through an aggregation service, etc.

Setting up jQuery Mobile

Now we can consume the service with jQuery Mobile and host our mobile application with Sinatra. There will be two parts to our jQuery Mobile application, the HTML page which performs the setup for jQuery Mobile and a script which consumes our service. Let’s first take a look at the HTML page:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Top 10 Cameras</title>
  <link rel="stylesheet"
    href="//code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
  </script>
  <script src="cameras.js"></script>
  <script src="//code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js">
  </script>
</head>
<body id="page_body">
  <div id="cameraListPage" data-role="page">
    <div data-role="header">
      <h1>Camera List</h1>
    </div>
    <div data-role="content">
      <ul id="cameraList"></ul>
    </div>
  </div>
  <div id="cameraDetailPage" data-role="page">
    <div data-role="header">
      <h1>Camera Detail</h1>
    </div>
    <div id="cameraDetailContent" data-role="content">
    </div>
  </div>
</body>
</html>

The logic above is really just standard jQuery Mobile. We specify two pages, a #cameraListPage and a #cameraDetailPage. The #cameraListPage has an empty <ul> element which we intend to dynamically fill with cameras from our service. Similarly, the details page has no content which will be dynamically determined by selecting a camera from the list.

Rendering the Camera List

Now let’s have a look at the script that populates this logic. You can view the script in its entirety by downloading the example. The render method populates our <ul> by invoking our newly created camera service:

function render() {
  $.getJSON('/cameras/top10.json', function(data) {
    this.cameraData = data;
		
    var cameraListHtml = '';

    $.each(this.cameraData, function(i, camera) {
      cameraListHtml += '<li><a data-index="' + i + 
        '">' + camera.title + '</a></li>';
    });
		
    var $cameraList = $('#cameraList').append(cameraListHtml).listview();

    $cameraList.find('a').click(function() {
      displayCameraDetailPage(this, data);
    });
  });
}

Notice that the service data is retrieved in the same manner as our example above. The key difference is that we dynamically construct list items for each camera with a link that holds the index of the camera it refers to. The list items are then appended to the #cameraList which is rendered as a jQuery Mobile listview.

Showing the Camera Details

The final step is displaying the camera details. The displayCameraDetailPage method is bound to each camera link that was generated. The method is passed the <a> element and the camera data we retrieved from the service.

function displayCameraDetailPage(element, cameraData) {
  var camera = cameraData[$(element).data('index')];

  var detailsHtml = 
    '<div data-role="content"><h2>' + camera.title + '</h2>' + 
    '<p><strong>Price:</strong> ' + camera.price + '</p>' +
    '<p>' + camera.description + '</p>' +
    '</div></div>';
	
  $('#cameraDetailContent').html(detailsHtml);

  $.mobile.changePage('#cameraDetailPage');
}

Here we make use of the jQuery data method to retrieve the index of the camera that was selected. A markup representation of the details of the camera is generated and the #cameraDetailPage content is updated. Once the update is complete, the jQuery Mobile changePage method is used to show the #cameraDetailPage.

Sinatra makes it easy to develop web applications quickly. Try it and your sure to get your next mobile application up and running in minutes.

Cleanup your jQuery by Deferring

The asynchronous nature of AJAX sometimes makes jQuery code a bit hard to follow. Embedding callbacks in AJAX calls starts off reasonable, but enough callbacks can quickly become unwieldy. If your code base is suffering from this issue, have a look at the jQuery Deferred API. jQuery Deferred is an implementation of the CommonJS Promises Spec.

The CommonJS Promises Spec attempts to put an API around the consistent pattern of handling asynchronous callbacks. In the case of jQuery Deferred we are generally talking about AJAX calls. Let’s look at an example that will help to clarify the scenario.

Traditional Approach

Let’s say you have two services you are invoking to show information on a map. One service provides the latitudinal and longitudinal coordinates (geolocation) of an address, while another service provides nearby businesses.

function findGeolocation(address){
    $.ajax({
      url: "http://solutionsfit.com/geolocate",
      data: {json: JSON.stringify({"address" : address})},
      type: "POST",
      success: function(geolocation) { 
        findNearbyBusinesses(address, geolocation);
      }
  });
}

function findNearbyBusinesses(address, geolocation){
    $.ajax({
      url: "http://solutionsfit.com/nearbyBusinesses",
      data: {json: JSON.stringify({"address" : address})},
      type: "POST",
      success: function(businesses) { 
        showLocationMap(geolocation, businesses);
      }
}

It’s difficult to follow the control structure of the above code due to the embedded callbacks. The $.when method from the jQuery Deferred API helps clean this up.

Using jQuery Deferred

Instead of embedding our control flow in the callback functions themselves, we can specify the flow through an API. The $.when method accepts a list of functions that return a Deferred object. The $.ajax API returns a Deferred object allowing us to directly pass the result of AJAX invocations to the $.when method.

Once an AJAX request completes, the Deferred object is considered “done”. The $.when method waits for all Deferred objects to reach the “done” state and then invokes any handler functions that have been specified for the following:

  • done – handlers always called once all Deferred objects complete
  • then – handlers called if all Deferred objects complete successfully
  • fail – handlers called if a failure occurs with one of the Deferred objects

Now let’s rewrite our above code snippet to use the $.when API.

function findGeolocation(address){
    return $.post(
        "http://solutionsfit.com/geolocate",
        {json: JSON.stringify({"address" : address})}
    );
}

function findNearbyBusinesses(address){
    return $.post(
        "http://solutionsfit.com/nearbyBusinesses",
        {json: JSON.stringify({"address" : address})}
    );
}

$.when(findGeolocation(address), findNearbyBusinesses(address))
    .then(function(geolocation, businesses) {
        showLocationMap(geolocation, businesses);
    });

Notice that the readability now clearly defines the control flow. This now reads as:

when we find the geolocation and any nearby businesses, then show the location and businesses on a map

In addition, in the second case we’ve improved performance by allowing our AJAX calls to execute simultaneously. In the first case, the retrieval of nearby businesses was forced to wait on the geolocation call due to the embedded callback.

There is much more to the API and you can review all the details here.

By |jQuery|Comments Off on Cleanup your jQuery by Deferring

Keep your layouts DRY with Rails and jQuery Mobile

jQuery Mobile presents a bit of a challenge when trying to keep your layouts DRY. In a general HTML document layout you have the head content, a header, a footer, and the page specific content. In other words, an HTML document is a single “page”. With jQuery Mobile you sometimes have several “pages” in a single HTML document for simplicity and/or performance reasons. Since each “page” often needs to follow the same layout, we need an approach to keep our UI code DRY.

Using the general Rails layout

Rails layouts assume the general HTML document structure. This works fine for an HTML document with a single jQuery Mobile “page”:

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <%= stylesheet_link_tag 'jquery-mobile-min', :media => 'screen' %>
    <%= javascript_include_tag 'jquery' %>
    <%= javascript_include_tag 'jquery.mobile.min' %>
  </head>
  <body>
    <div id="<%= page_id %>" data-role="page">
      <div data-role="header" class="main-header">
        <%= image_tag 'solutionsfit-logo.png' %>
      </div>

      <div data-role="header" data-position="inline">
        <%= yield :header %>
      </div>

      <% flash.each do |key, value| %>
        <%= content_tag(:div, value, :class => "flash #{key}") %>
      <% end %>

      <div data-role="content">
        <%= yield %>
      </div>

      <div data-role="footer">
        <h4>© <%= Date.today.year %> solutionsfit</h4>
      </div>
    </div>
  </body>
</html>

This works fine as long as you only have a single jQuery Mobile “page” in your HTML. Unfortunately, this is often not the case. When you want to include multiple jQuery Mobile “pages” in a single HTML document while keeping your layout DRY, you have to be a little more creative.

Using the CaptureHelper for multiple “pages”

Fortunately there is a solution using the CaptureHelper. From the Rails documentation:

CaptureHelper exposes methods to let you extract generated markup which can be used in other parts of a template or layout file.

This allows us to create a partial that describes our general “page” structure, shared/_page.html.erb:

<div id="<%= page_id %>" data-role="page">
  <div data-role="header" class="main-header">
    <%= image_tag 'solutionsfit-logo.png' %>
  </div>

  <div data-role="header" data-position="inline">
    <%= header %>
  </div>

  <% flash.each do |key, value| %>
    <%= content_tag(:div, value, :class => "flash #{key}") %>
  <% end %>

  <div data-role="content">
    <%= content %>
  </div>

  <div data-role="footer">
    <h4>© <%= Date.today.year %> solutionsfit</h4>
  </div>
</div>

As you can see we define variables for header and content. To use the partial we simply use the capture method from the CaptureHelper:

<% @home_header = capture do %>
  <h2>solutionsfit</h2>
<% end %>

<% @home_content = capture do %>
  <p>Welcome to solutionsfit!</p>

  <ul data-role="listview" data-inset="true">
    <li><a href="#postings">Blog Postings</li>
  </ul>
<% end %>

<%= render 'shared/page', :page_id => "home_page", 
  :header => @home_header, :content => @home_content %>

<% @blog_header = capture do %>
  <h2>Blog Postings</h2>
<% end %>

<% @blog_content = capture do %>
  <!-- Logic to list postings here -->
<% end %>

<%= render 'shared/page', :page_id => "postings", 
  :header => @blog_header, :content => @blog_content %>

Refactoring the general layout

Now that we have our partial defined, we can refactor our general layout to include just the basic HTML document structure:

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <%= stylesheet_link_tag 'jquery-mobile-min', :media => 'screen' %>
    <%= javascript_include_tag 'jquery' %>
    <%= javascript_include_tag 'jquery.mobile.min' %>
  </head>
  <body>
    <%= yield %>
  </body>
</html>

While it’s not as pretty as a general template, it allows us to DRY up our jQuery Mobile views. Another option is using a partial layout, but this has the disadvantage of requiring you to make both your header and content partials themselves. This tradeoff wasn’t worth the additional files in my case.

Mobile Grails at Dallas Techfest

Thanks to all who attended my presentation on Saturday at Dallas Techfest. As promised you can find the slides and source code at the links below:

Presentation Slides
Source Code

Enterprise Mashups at Dallas TechFest

Thanks to all who attended my Enterprise Mashups with RESTful Web Services and jQuery presentation at Dallas Techfest. The following links provide access to all presentation materials:

Presentation Slides
Live Example
Download Example Zip

By |jQuery, REST|Comments Off on Enterprise Mashups at Dallas TechFest

Enterprise Mashups with RESTful Web Services and jQuery (Part 2)

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.

Enterprise Mashups with RESTful Web Services and jQuery (Part 1)

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 introduces what is required of your enterprise services, the simplicity of JSON, and how to consume your RESTful web services using jQuery. Part 2 will cover consuming services from across the enterprise with JSONP, accessing secure resources, and handling error conditions.

Enterprise Web Services: Got REST?

First things first, we need RESTful web services to provide the data we intend to consume. Are there already web services exposed in your enterprise that provide a RESTful API? Do these services support JSON? If not, there are a wide array of technologies that make it simple to expose RESTful web services from your existing applications.

If you have RESTful web services, but they only support an XML result it is quite simple to support JSON with JAX-RS. JAX-RS uses the HTTP Accept header to determine what media type should be sent back as a result. The following HTTP header entry would indicate that the client is requesting a JSON result:

Accept: application/json

RESTEasy provides a portable JAX-RS implementation that makes it simple to expose services supporting a variety of media types. If you happen to be using Seam, exposing RESTful services through RESTEasy is a no-brainer. See the Seam documentation for more details.

Why use JSON when you have XML?

It is now common to expose REST services that return a result in JSON format. The format is described as a lightweight data-interchange format. The major advantage to JSON is that it is JavaScript native format. This means if a RESTful service is invoked through a JavaScript AJAX call and returns a JSON result, the data returned by the service can be used without additional parsing.

For example, we could have the following URL tied to a consultants list resource.

http://solutionsfit.com/services/rest/consultants

When a GET request is received for this URL the following JSON response is generated.

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

If this JSON result was stored in a JavaScript variable named solutionsfitConsultants, I could alert the user of Jacob Orshalick’s blog URL with the following JavaScript snippet.

var consultant = solutionsfitConsultants[0].consultant;

alert(consultant.firstName + ' ' + consultant.lastName);

Obviously this makes it very easy to render results to the user by removing the additional step of parsing that is required with XML.

Request and display JSON data with jQuery

jQuery makes it simple to consume a RESTful service providing a JSON result through a simple AJAX call. Let’s look at an example. The following HTML provides the shell for the service results I want to display in my mashup.

<table width="100%">
  <thead>
    <tr>
      <th>
        Consultant
      </th>
      <th>
        Blog Feed
      </th>
    </tr>
    <tbody id="consultants">
    </tbody>
</table>

The jQuery getJSON function makes it simple to consume the service that provides us the list of consultants. The getJSON function sends an AJAX GET request to the resource URL with an HTTP Accept header of application/json.

jQuery.getJSON(
  'http://solutionsfit.com/services/rest/consultants&callback=?',
  function(data) {
    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);
    });
  }
);

Notice that we also use the jQuery each function to loop through the JSON results. Each result in the returned JSON array is set into the variable item.

We then generate the HTML to add to the table for each consultant and set it into the consultantHtml variable. We then select the

element that will contain the consultant results using it’s element ID and use the jQuery append function to append the consultantHtml.

When the page is fully rendered, the resulting HTML will be:

<table width="100%">
  <thead>
    <tr>
      <th>
        Consultant
      </th>
      <th>
        Blog Feed
      </th>
    </tr>
    <tbody id="consultants">
      <tr>
        <td>
          Jacob Orshalick
        </td>
        <td>
          <a target="_blank" 
              href="http://solutionsfit.com/blog/feed/">
            Blog Link
          </a>
        </td>
      </tr>
      <tr>
        <td>
          Nirav Assar
        </td>
        <td>
          <a target="_blank" href=
            "http://assarconsulting.blogspot.com/feeds/posts/default/">
            Blog Feed
          </a>
        </td>
      </tr>
    </tbody>
</table>

Note that only JavaScript libraries and HTML have been used to consume the service. This provides the flexibility to render this content in a web application, a portal, or even a static HTML page!

That’s it for round one of enterprise mashups. Stay tuned for part 2 which will discuss how to gather data from across the enterprise with JSONP and how accessing secured services is made easy.