Tabular data composition in the browser for SOA

Problem example: Need to compose data from several services in a table, where each row contains data from several services. For example a product listing in a shopping basket:

General solutions for composition:

  • Custom server-side
  • Modules in the IIS pipeline
  • Client side with CSS
  • Client side with JavaScript

I will not discuss advantages and disadvantages for each solution in this post, but rather focus on a specific technique to solve it client side with JavaScript.

The benefits of composing in the browser are many, for example you don’t take any dependencies between services on the server-side. This allows you to get away with a lot less server resources; you are delegating this work to the web browsers (which is generally underused). Now your web front-end and data services can be scaled differently according to your need.

Example data

The example given here is very simplified, just to focus you in on the idea/concept.

The Sales service will provide the initial data which makes up the shopping basket: 2 records with ProductID and Price.

[{ "Products": [{ "ProductId": "1234", "Price": "3.99$" }, { "ProductId": "5678", "Price": "149.99$"}]

Now we have the ProductId’s that we can use to get data from the Marketing service.  The data returned may look like this:

[{ "ProductId": "1234", "Name": "Super fix it", "Description": "Another cleaning spray" }, { "ProductId": "5678", "Name": "Max2000", "Description": "Powerful vacum cleaner" }]

Composing

So how can we compose these pieces of data in a table? We could manipulate the DOM directly using i.e. jQuery, but this could get really messy pretty fast. Luckily there are JavaScript frameworks out there that can help. I have looked into using Knockout, it enables you to use the MVVM pattern in the browser.

This means that we only have to worry about updating the view model (would be a JavaScript class) with the data we got from the services and let Knockout worry about which DOM elements that needs to be updated as it binds the view model to several html elements.

First, we could set up a template for the html we want (knockout integrates with jQuery template engine):

<div data-bind='template: "shoppingCartTemplate"'>
</div>
<script id="shoppingCartTemplate" type="text/javascript">
// <![CDATA[
<h2>Shoppingbasket</h2>
<table border=1 cellpadding=2 cellspacing=0>
{{each shoppingCart}}
<tr>
<td>${ ProductId }</td>
<td><b>${ ProductInfo().Name }</b>
    ${ ProductInfo().Description }</td>
<td>${ Price }</td>
</tr>
{{/each}}
</table>
// ]]>
</script>

The first div tag is put wherever you want the table to appear on the page, the rest could be put e.g. in the header.

Then we define a viewmodel for the shopping cart – an observable array of products. After that, tell the knockout framework to activate its databinding to our viewmodel:

// Declare viewmodel with empty shoppingcart and bind it via knockoutjs
var viewModel = {
	shoppingCart: ko.observable([])
};

ko.applyBindings(viewModel);

Now, it is time to get the data (if it was not returned with the page HTML) and update our viewmodel. Please read the comments in code to follow the steps.

Update 2011-09-24: Thanks to “David L” (see comments below) who pointed me to the Mapping plugin for knockoutjs. It looks like you can use this instead of manually writing the merge-code.

// Declare viewmodel template that we will use to extend the first json structure to
var shoppingCartViewModelTemplate = { "ProductId": "", "ProductInfo": ko.observable({ "Name": "", "Description": "" }) };

// 1. Get products in customers shopping cart from the sales service
// Using inline json here to make it easier for you to play with
// Typically you would do an AJAX call like $.getJSON('/CustomerShoppingCart/12345', function (data) {...
var shoppingCart = { "Products": [{ "ProductId": "1234" }, { "ProductId": "5678"}] };

var numberOfProducts = shoppingCart.Products.length;

for (var x = 0; x < numberOfProducts; x++) {

    // expand the json structure served from the first service to have all the fields/properties of the viewmodel
    shoppingCart.Products[x] = extendJsonDataWithTemplateFields(shoppingCart.Products[x], shoppingCartViewModelTemplate);
}

// Makes it appear in the browser since the viewmodel is bound to html elements
viewModel.shoppingCart(shoppingCart.Products);

// 2. Get products in customers shopping cart from the Marketing service
// Typically you would do an AJAX call like $.getJSON('/MarketService/BasicProductInfo/' + listOfIds, function (data) {...
var productInfoData = { ProductInfo: [{ "ProductId": "1234", "Name": "Super fix it", "Description": "Another cleaning spray" }, { "ProductId": "5678", "Name": "Max2000", "Description": "Powerful vacum cleaner"}] };

// Update each product in the viewmodel with the name and description
for (var x = 0; x < numberOfProducts; x++) {

    // NB! assuming the data will be returned in the order we queried
    viewModel.shoppingCart()[x].ProductInfo(productInfoData.ProductInfo[x]);

}

// Helper function to extend a json datastructure with a "template"
function extendJsonDataWithTemplateFields(jsonData, template) {

for (var templateMember in template) {

    if (!jsonData.hasOwnProperty(templateMember)) {
        //add new datamember to json data from the template
        jsonData[templateMember] = ko.observable(template[templateMember]);
    } else {
        // template member already exists in jsonData, we only need to wrap it in an observable
        // This step is only needed if you want to further update the data
        jsonData[templateMember] = ko.observable(jsonData[templateMember]);
    }
}
return jsonData;
}

There it is – a basic conceptual example of composing data from several sources – in a table using the browser.

This approach have been used in production with success.

Improvements and considerations

  • Off course you have to pay attention to the same possible issues that you do server-side, e.g: data can come in different order and data may never come at all
  • With big data sets you may want to pay attention to how many times the different DOM elements are being rendered.
  • Receiving several datasets (e.g. json structures) asynchronously may result in several javascript functions trying to update the viewmodel simultaneously.
  • More efficient JavaScript joins
  • Etc…
About these ads

5 Responses to “Tabular data composition in the browser for SOA”

  1. We did a very similar PoC on this, we ended up using the knockout plugin called Mapping (made by the same people i think) to do the merging of datasets. Did you have a look at that?

    Nice article!

    David

  2. No, I did not know about that plugin. This was a post related to a solution I made back before this plugin existed I think.

    It looks like it can do the job so I am really happy if I can throw out the custom merging of datasets code :-) I will update the article.

    Great tip!

  3. interesting. How do you deal with paging/sorting?

  4. Nice article and very relevant to some things we are working on in my shop. I’m also curious how you would address paging and sorting. We’ve struggled to come up with a performant solution.

Trackbacks/Pingbacks

  1. SOA UI Composition | Joe's Blog - February 13, 2013

    […] pointed us in a good direction during his course to a blog post written by Freddy Hanson (here). In this post Freddy Hanson talks about returning JSON from your services and composing them on […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: