A beginner's guide to Google Api using a service account (Node.js) - Part 2

The last few days I have been working towards creating a Node.Js server that can poll and update various google apps (Calendar, Drive, Admin and Coordinate in particular), and I was a little surprised to find very little out there talking about how to do so. Even worse was there were a lot of guides or questions that seemed like they were using out of date code. So in order to log my process for myself in the future, and hopefully help someone else out, here is a step by step guide to how I managed to set it up. This set up was done on an Windows Server 2008, but a lot of these steps will work for any set up.

Part 2 will primarily talk about the coding and preparation required to use the APIs. It is assumed that you have already created a basic Node server.

Step 1 - Prepare the key file

In the last part you would have at one point got your hands on a .p12 file. In order to use this file we will have convert it to something that Node can understand, which in this case will be a .pem file. First you will need to get your hands on OpenSSL (which will differ depending on your system, but for windows you can get it from http://www.openssl.org/related/binaries.html).

Now you need to use OpenSSL to convert your file using:

openssl pkcs12 -in yourp12file.p12 -nocerts -passin pass:notasecret -nodes -out newKey.pem

Note the 'notasecret' password is the current password being given out when you create a p12 file during the google developer set up in the last pass, if you are given a different password you may need to substitute this text.

Once you have the .pem file place it somewhere you can access it within your node server directory.

Step 2 - Prepare the Server

Now you need to move to your node server, first you need to get ahold of your google api nodule, which can be installed via NPM with:

npm install googleapis

Lets have a look at the module quickly. Within the nodule's folder (node_modules/googleapis/) you should find an api directory. This directory will list all the possible applications you can use within this nodule, so if you ever need to look at possible apis you can navigate this section and explore it to garner some idea of calls you can make. Now you need to set up various nodules within the node server, in my case I had to set up drive, calendar, directory and coordinate.

var googleapis = require('googleapis')
 , drive = googleapis.drive('v2')
 , calendar = googleapis.calendar('v3')
 , directory = googleapis.admin('directory_v1')
 , coordinate = googleapis.coordinate('v1')

The initial googleapis connection allows you to pass arguments such as authorisation, while the rest are application specific. If you are wondering where the 'v2', 'directory_v1' etc. are coming from, they are the .js file names found within the api directory.

Step 3 - Authentication with Google

Now you can begin some coding. Evertime you connect to google you need to present some form of authorising using a JWT header. To create this header you need something like the following code:

authClient = new googleapis.auth.JWT(
    SERVICE_EMAIL,
    PATH_TO_KEY_FILE, 
    KEY_FILE_CONTENTS,
    API_SCOPES,
    USER_TO_IMPERSONATE
);

So lets break this down a little better, the options listed above are:

SERVICE_EMAIL: This should be the service account email copied in part 1 PATH_TO_KEY_FILE: This is one of the two ways you can present the .pem file, this is path based KEY_FILE_CONTENTS: This is the other option, this should be a link to the date contained within the .pem file (personally I used a fs.readFile here) API_SCOPES: This should be a list of all the API scopes used, this list should look like the scopes entered during the Google admin section. It can be a comma delimited string or an array USER_TO_IMPERSONATE: This section is optional, but from my own experience I had a lot of trouble dealing with Google Admin and Google Coordinate without providing an email address here for an administrator.

Please note that you can use the path to the key file or the key file contents, whichever you don't use should be null. Originally I was using the path, but I would get the occasional crash with the error:

var ret = this._binding.sign(toBuf(key));

TypeError: Not a buffer

Which was resolved simply by changing to the key file contents using fs.readFile, I have not seen the error since.

Now finally you need to pass this JWT header through the authorization function, which should look something like:

authClient.authorize(function(err, tokens) {
      if (err) {
         //Handle error
  }

Now you should be ready to make calls to the various apis that you are linked with, while there are more than I could possibly list in this short blog post, here is an example for listing and inserting calendar events:

calendar.events.list({
    calendarId: googleUserId,
    maxResults: 20,
    fields: "items(end,start,status,summary)",
    auth: authClient
}, function(err, resp) {
    if (err == null) {
        //Handle response
    } else {
        //Handle error
    }
});

calendar.events.insert({
    calendarId: googleUserId,
    resource: {
        summary: name,
        description: name,
        reminders: {
            overrides: {
                method: 'popup',
                minutes: 0
            }
        },
        start: {
            dateTime: startDate
        },
        end: {
            dateTime: endDate
        }/*,
        attendees: [{
            email: '****@**********.com'
        }]*/
    },
    auth: authClient
 }, function(err, resp) {
    if (err == null) {
        //Handle response
    } else {
        //Handle error
    }
});

A couple of quick notes for these calls. The googleUserId is the email address of the user whose calendar I wish to view/alter, the start and end dates are dates which have been formatted using date.js to match rfc3339 specs.

More information about these calls can be found within the calendar folder within the api directory previously mentioned. You can find a comprihensive list of possible calls as well as various optional and required parameters.