December 14, 2011

Displaying Service-Based Data, Part 2

In the first part of this series I talked about the importance of normalizing service-based data from different sources. The obvious question at this point is "normalized to what?", and that's the subject of this post.

When we talk about displaying "data", we're usually talking about the visual display of quantitative information. A table. A chart. A map. Something which makes visual comparisons between discreet items possible. When we're displaying categories (as in a table) we're often called upon to sort the data according to one or more properties. In a time-series we need to make sure that the sequence in which we display values matches their order. So, more often than not the order in which items are displayed is important, and we're talking about an array for our primary data structure.

What about the case where there's just a single item and we're displaying its properties? It's tempting to use a map, but it's almost always a bad idea. An array with one item in it works just fine and leaves you the ability to use the same structure for multiple items.

For example, using the Weather Underground data from the previous post, a request for weather data from a single station returns:

{
  response: { ... some stuff ... },
  location: { ... some stuff ... },
  current_observation: {
    ... some stuff ... 
  }
}

And the request for a list of weather stations returns:

{
  response: {... some stuff ...},
  location: {
    ... some stuff ...
    nearby_weather_stations: {
      airport: {
        station: [
          { ... result 1 stuff ... },
          { ... result 2 stuff ... }
        ]
      },
      pws:{
       station:[
          { ... result 1 stuff ... },
          { ... result 2 stuff ... }
       ]
      }
      ... some more stuff ... 
    }
  }
}

A normalized data structure for both of these cases might look like:

{
  response: {
    meta: { ... some stuff ... },
    results: [
      { ...result 1 stuff... },
      { ...result 2 stuff... },
      { ...result 3 stuff... },
      { ...result 4 stuff... }
    ]
  }
}

The normalization functions which would return the above data structure for the list of weather stations might look like:

plugins.wunderground = {

  stations: {
    formatData: function(data){
      var airports = data.location.nearby_weather_stations.airport.station,
          pws = response.location.nearby_weather_stations.pws.station,
          i = 0,
          formattedData = {
            respone: {
              meta: {whatever},
              results: []
            }
          };
      for(i=0;i<airports.length;i++){
        formattedData.response.results.push(airports[i]);
      }
      for(i=0;i<pws.length;i++){
        formattedData.response.results.push(pws[i]);
      }
    return formattedData;
    }
  },

  station: {
    formatData: function(data){
      var results = data.current_observation,
          formattedData = {
            respone: {
              meta: {whatever},
                results: []
              }
            };
      formattedData.response.push(results);
      return formattedData;
    }
  }

};

All this might seem like overkill until you realize it allows you to do something like this:

var dataSrc = "wunderground";
var id = "KSFO";

$.ajax({
  url: plugins[dataSrc].stations.url(id),
  dataType: plugins[dataSrc].dataType,
  success: function(response){
    var data = plugins[dataSrc].stations.formatData(response);
    var stations = new Backbone.Collection;
    for (var i=0;i<data.response.results.length;i++){
      var station = new Backbone.Model; 
      station.url = plugins[dataSrc].station.url(data.response.results[i].id); 
      stations.add(station);
    }
  }
});

Without worrying about the format in which data is returned from a service. If the Weather Underground changes its data format, we only need to change the formatData() method in the plugin. If we go with a different data provider, we only need to write a plugin for that provider and change dataSrc.

So what do we do once we've got this far? In the next post I'll talk about getting data from those data models onto the screen.

No comments:

Post a Comment