Backbone.js Tutorial: Google's APIs and RequireJS

Date: Wed Sep 20 2017 Node.JS

In Part 1: Build Environment, I explained how to set up a simple Node server to host your Backbone.js app and test suite. Something that confused people was the way I used relative paths, which meant the tests could fail if you didn't visit ``` /test/ ``` ( ``` /test ``` won't work). There was a reason for this: I developed the original version to run on Dropbox, so I wanted to use relative paths. It's probably safer to use absolute paths, so I should have made this clearer.

In this part you'll learn the following:

  • How ``` Backbone.sync ``` works
  • How to load Backbone.js and Underscore.js with RequireJS
  • How to get started with Google's APIs

The ``` Backbone.sync ``` Method

Network access in Backbone.js is nicely abstracted through a single method which has the following signature:

Backbone.sync = function(method, model, options) {};

The ``` method ``` argument contains a string that can be one of the following values:

  • ``` create ```
  • ``` update ```
  • ``` delete ```
  • ``` read ```

Internally, Backbone.js maps these method names to HTTP verbs:

var methodMap = {  'create': 'POST',  'update': 'PUT',  'delete': 'DELETE',  'read':   'GET'};

If you're familiar with that particular flavour of RESTful API then this should all look familiar.

The second argument, ``` model ``` , is a ``` Backbone.Model ``` or ``` Backbone.Collection ``` - collections are used when reading multiple values.

The final argument, ``` options ``` , is an object that contains success and error callbacks. It's ultimately handed off to the jQuery Ajax API.

To work with Google's APIs we need to write our own ``` Backbone.sync ``` method. In general terms our implementation should be structured like this:

Backbone.sync = function(method, model, options) {  switch (method) {    case 'create':      googleAPI.create(model, options);    break;    case 'update':      googleAPI.update(model, options);    break;    case 'delete':      googleAPI.destroy(model, options);    break;    case 'read':      // The model value is a collection in this case      googleAPI.list(model, options);    break;    default:      // Something probably went wrong      console.error('Unknown method:', method);    break;  }};

The ``` googleAPI ``` object is fictitious, but this is basically how ``` Backbone.sync ``` is usually extended - a lightweight wrapper that maps the method names and models to another API. Using a lightweight wrapper means the underlying target API can be easily used outside of a Backbone.js.

In our case, Google actually provides a JavaScript API - there will be a ``` gapi.client ``` object available once the Google APIs have been loaded.

Setting Up A Google API Account

The main page for Google's developer documentation is at, but what we're interested in is the Google Tasks API which can be found under Application APIs.

Google's Application APIs are designed to work well with both server-side scripting and client-side JavaScript. To work with the Google Tasks API you'll need three things:

  1. A Google account (an existing one is fine)
  2. Google API Console access (you may have already enabled it if you work with Google's services)
  3. An API key

To set up your account to work with the Google API Console, visit Once you've enabled it, scroll down to Tasks API:

Google Tasks API switch

Then switch the button to on, and accept the terms (if you agree to them). Next, click API Access in the left-hand navigation bar, and look under Simple API Access for the API key. This "browser apps" key is what we need. Make a note of it for later.

OAuth 2.0 for Client-side Applications

Still in the API Access section of the console, click the button to create an OAuth 2.0 project. Enter "bTask" (or whatever you want) for the product name, then ``` http://localhost:8080 ``` for the URL. In the next dialog, make sure ``` http:// ``` is selected instead of ``` https:// ``` , then enter ``` localhost:8080 ``` and click "Create client ID".

You'll now see a set of values under "Client ID for web applications". The field that says "Client ID" is important - make a note of this one as well.

You should now have an API key and a Client ID. These will be used to load Google's APIs and allow us to use an OAuth 2.0 service from within the browser - we won't need to write our own server-side code to authenticate users.

Follow Along

If you want to check out the source from Part 1 so you can follow along, you can use Git to get the exact revision from last week:

git clone dailyjs-backbone-tutorialgit reset --hard 2a8517e

Required Libraries

Before progressing, download the following libraries to ``` app/js/lib/ ``` :

Open ``` app/js/main.js ``` and edit the ``` shim ``` property under ``` requirejs.config ``` to load Underscore.js and Backbone.js:

requirejs.config({  baseUrl: 'js',  paths: {  },  shim: {    'lib/underscore-min': {      exports: '_'    },    'lib/backbone-min': {      deps: ['lib/underscore-min']    , exports: 'Backbone'    },    'app': {      deps: ['lib/underscore-min', 'lib/backbone-min']    }  }});require([  'app'],function(App) {  window.bTask = new App();});

This looks weird, but remember we're using RequireJS to load scripts as modules. RequireJS "shims" allow dependencies to be expressed for libraries that aren't implemented using AMD.

Loading the Tasks API

The basic pattern for loading the Google Tasks API is:

  1. Load the Google API client library: ``` ```
  2. Call ``` gapi.client.load ``` to load the "tasks" API
  3. Set the API key using ``` gapi.client.setApiKey() ```

To implement this, you'll need a place to put the necessary credentials. Create a file called ``` app/js/config.js ``` and add the API key and Client ID to it:

define([], function() {  var config = {};  config.apiKey = 'your API key';  config.scopes = '';  config.clientId = 'your client ID';  return config;});

This file can be loaded by our custom Google Tasks API/Backbone.sync implementation.

Now create a new file called ``` app/gapi.js ``` :

define(['config'], function(config) {  function ApiManager() {    this.loadGapi();  }  _.extend(ApiManager.prototype, Backbone.Events);  ApiManager.prototype.init = function() {  };  ApiManager.prototype.loadGapi = function() {  };  Backbone.sync = function(method, model, options) {    options || (options = {});    switch (method) {      case 'create':      break;      case 'update':      break;      case 'delete':      break;      case 'read':      break;    }  };  return ApiManager;});

This skeleton module shows the overall layout of our Google Tasks API loader and ``` Backbone.sync ``` implementation. The ``` ApiManager ``` is a standard constructor, and I've used Underscore.js to inherit from ``` Backbone.Events ``` . This code will be asynchronous, so event handling will be useful later.

The ``` loadGapi ``` method loads Google's JavaScript using RequireJS. Once the ``` gapi ``` global object has been found, it will do the rest of the configuration by calling the ``` init ``` method:

ApiManager.prototype.loadGapi = function() {  var self = this;  // Don't load gapi if it's already present  if (typeof gapi !== 'undefined') {    return this.init();  }  require([''], function() {    // Poll until gapi is ready    function checkGAPI() {      if (gapi && gapi.client) {        self.init();      } else {        setTimeout(checkGAPI, 100);      }    }        checkGAPI();  });});

All the ``` init ``` method needs to do is load the Tasks API with ``` gapi.client.load ``` :

ApiManager.prototype.init = function() {  var self = this;  gapi.client.load('tasks', 'v1', function() { /* Loaded */ });  function handleClientLoad() {    gapi.client.setApiKey(config.apiKey);    window.setTimeout(checkAuth, 100);  }  function checkAuth() {    gapi.auth.authorize({ client_id: config.clientId, scope: config.scopes, immediate: true }, handleAuthResult);  }  function handleAuthResult(authResult) {  }  handleClientLoad();};

The ``` config ``` variable was one of the dependencies for this file, and contains the credentials required by Google's API.

Loading the API Manager

Now open ``` app/js/app.js ``` and make it depend on ``` gapi ``` , then create an instance of ``` ApiManager ``` :

define([  'gapi'],function(ApiManager) {  var App = function() {    this.connectGapi();  };  App.prototype = {    connectGapi: function() {      this.apiManager = new ApiManager();    }  };  return App;});

If you want to check this works by running the tests, you'll need to change ``` test/setup.js ``` to flag ``` gapi ``` as a global:

var assert = chai.assert;mocha.setup({  ui: 'tdd', globals: ['bTask', 'gapi', '___jsl']});

However, I don't intend to load the API remotely during testing - this will effectively be mocked. I'll come onto that in a later tutorialgapi loaded/posts/gapi-loaded.png">

If you run the app or tests and open a JavaScript console, a ``` gapi ``` global object should be available. Using Google's APIs with RequireJS and Backbone.js seems like a lot of work, but most of this stuff is effectively just configuration, and once it's done it should work solidly enough, allowing you to focus on the app design and development side of things.

Full Source Code

Commit 9d09a6.