Monday, January 26, 2015

Using Ember Data as a simple "cookie" method

For a recent Ember web app, I needed to store a count for how many times a certain event happened. I needed this count to persist across sessions, and I began to think back to the Todo MVC Ember tutorial I had once gone through. In the tutorial, items in a todo list were saved using Ember Data and a local storage adapter. After doing a little research, I decided this would be an appropriate way for me to approach this task. If you aren't already using Ember Data, download the js file. In addition to Ember Data, I went to Emberjs.com to find the link to the local storage adapter that was used in the tutorial. You can find it here. In order to use it, you need to tell your application that you are using it in your application.js file.
App.ApplicationAdapter = DS.LSAdapter.extend({
  namespace: 'example-emberjs'
});
To keep track of my count, I created an object called Cookie to store my count. This object must extend DS.Model in order to work with the Ember data store. I simply store one variable in the object, numberToCount.
App.Cookie = DS.Model.extend({
  numberToCount: DS.attr('number')
});
In order get my count as soon as the app was starting, I overrode the ApplicationRoute, which I was not yet doing. The only thing I do here, is call the updateCount function on my controller.
App.ApplicationRoute = Ember.Route.extend({

  setupController: function(controller, model) {
    this._super(controller,model); 
    controller.send('updateCount');
  }

});
And in my ApplicationController, I implemented an updateCount function. What I am doing here is using built in Ember Data functions to find all cookie objects, of which there should be zero or one in my case. If there are zero cookie objects, it means I haven't created one yet, so I do so, and set the numberToCount to 0. If there is a cookie object, then I increment the numberToCount field. In both cases, I save the cookie object, then set a variable "myCount" on the application controller, so that the count is accessible from all my other controllers.
  updateCount: function() {
    var self = this;
    self.store.find('cookie').then(function (cookies) {
      var cookie;
      if(cookies.content.length > 0) {
        cookie = cookies.content[0];
      } else {
        cookie = null;
      }
      
      if(cookie == null) {
        cookie = self.store.createRecord('cookie', {
          numberToCount: 0,
        }); 
      } else {
        cookie.set("numberToCount", cookie.get("numberToCount") + 1);
      }
      cookie.save();
      self.set("myCount", cookie.get("numberToCount"));
    });
    
  }
And there you have it, a simple way to persist a "cookie" across application sessions.

Monday, December 8, 2014

Retrieving Google Analytics data from a Node.js backend

I've recently added the ability for a web app to display Google Analytics information, such as the number of sessions and users for a monitored application. My backend to this web app happens to be Node, and the documentation for getting this to work is pretty non-existent. I hope this post enables others to be able to easily integrate this type of feature into their Node applications!

First, in your package.json, add the dependency for "googleapis". For all google analytics integration, I created a ga.js file, and placed it in ./api/controllers. In my main Node app, app.js, I created a reference to this
var ga = require('./app/controllers/ga.js');


I then use this reference for an API GET as follows
app.get('/analytics/sessionsAndUsers/startDate/:startDate/endDate/:endDate', ensureAuthenticated, ga.getSessionsAndUsers);
Here, I created the endpoint and pass in a startDate and endDate to my function getSessionsAndUsers. I also call ensureAuthenticated, which validates the user making the GET call is logged in - this is set up using Passport.js, a completely different topic.

In order for the above to work, I need to create my function getSessionsAndUsers in ga.js
module.exports.getSessionsAndUsers = function(req, res, next) {

  ...

};

Now, I need to build out the guts for this to work. First, a little pre-setup needs to happen. You need to go to the Google Dev Console and enable the Analytics API. Then on the Credentials page, create a new Client ID, of type Service Account. This will provide you with a email address and automatically download a private key. Follow the steps here to convert this key to a .pem file. Additionally, go into your Google Analytics account and add the @developer.gserviceaccount.com email address as a user.

Once the above is done, we can build out the JavaScript. In ga.js, add the following to the top of the file, replacing with your service account email address and .pem path, as well as the profile Id of the analytics you want to monitor.
var google = require('googleapis');
var SERVICE_ACCOUNT_EMAIL = '*********@developer.gserviceaccount.com';
var SERVICE_ACCOUNT_KEY_FILE = '/MYPATH/googleapi-privatekey.pem';
var jwt = new google.auth.JWT(
        SERVICE_ACCOUNT_EMAIL,
        SERVICE_ACCOUNT_KEY_FILE,
        null,
        ['https://www.googleapis.com/auth/analytics.readonly']);

var analytics = google.analytics('v3');
var gaId = 'YOUR_PROFILE_ID';
Now, we are ready to finish up the getSessionsAndUsers function. Here is an example:
module.exports.getSessionsAndUsers = function(req, res, next) {
  var startDate = '2014-12-08';
  var endDate = '2014-12-08';
  try { startDate = req.params.startDate ? req.params.startDate : null; }
  catch (err) {
    res.send(404, 'startDate not found');
    return;
  }
  try { endDate = req.params.endDate ? req.params.endDate : null; }
  catch (err) {
    res.send(404, 'endDate not found');
    return;
  }

  jwt.authorize(function(err, result) {
    if(err) {
      console.log(err);
      return;
    }
    analytics.data.ga.get({
      auth: jwt,
      'ids': 'ga:' + gaId,
      'start-date': startDate,
      'end-date': endDate,
      'metrics': 'ga:sessions,ga:users'

      }, function(err, result) {
        if(!err){
          res.status(201).send(result);
        }
        else{
          next();
        }
    });
  });

};

And that's it! You will be able to make a call from your web app to this node backend like so:
var promise =  $.getJSON("analytics/sessionsAndUsers/startDate/"+startDate+"/endDate/"+endDate);