Part 1: 构建环境中, 我们解释了怎么样node web服务器去访问backbone.js应用程序和写测试用例,在这个里面我又一个小小的问题就是我们用了相对路径,这就意味这当我们访问不到/test/(或者/test)时测试是不能通过的。之所以用相对路径的原因是我开发的原始版本是运行在Dropbox上的。为了更加的方便建议你改成绝对路径。

在这一部分我们将要讲到得:

  • Backbone.sync方法
  • 怎样用RequireJS加载Backbone.js和Underscore.js
  • Google’s APIs入门

Backbone.sync方法

在Backbone.js的网络访问就是同这个方法来实现的:

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

其中method是一个字符串,它可以是下列值之一:

  • create
  • update
  • delete
  • read

在Backbone.js内部,与HTTP相对应方法的名称如下:

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

如果你对RESTful API比较熟悉的话,应该觉得是曾相识。

第二个参数model的值是Backbone.Model或Backbone.Collection(读取多个值集合时使用)

最后一个参数options是一个对象,包含了成功和失败时候的回调,最终会返回jQuery的Ajax API。

为了能够使用Google’s APIs需要写一个我们自己的Backbone.sync方法。一般情况下大概的结构如下:

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;
  }
};

当然googleAPI是我们虚拟的一个对象,这样我们基于这个Backbone.sync就可以扩展封装出一个轻量级的映射到其他API的maps包。通过这个封装我们就能更方便的在Backbone.js外部使用其他API。

在这个例子中,其实Google给我们提供了一个JavaScript API—Google APIs加载成功之后我们将会有个一gapi.client对象

新建一个Google API账号

谷歌的开发者文档首页是developers.google.com,我们需要的Google Tasks APIApplication APIs下。

Google’s Application APIs被设计在服务器端脚本和客户端的JavaScript都良好的运行,要使用Google Tasks API需要完成以下三件事情:

  1. 一个Google账户(可以使已经注册的)
  2. Google API Console访问权限(如果你用过Google’s services,直接使用即可)
  3. 一个API key

要到Google API Console下取设置你的账号,请访问code.google.com/apis/console,一旦你启用你的账号后,页面往下滚动即可看到Tasks API:

enter image description here

然后接受条款(如果你同意)就点击切换按钮将状态调至on。接下来在点击你左侧导航中得API Access记录下Simple API Access的API key。这个“浏览器应用程序”key就是我们后面会用的API key。

客户端应用程序下使用OAuth 2.0用户认证

还是在Google API Console的API Access下,点击按钮创建一个OAuth 2.0项目,项目名称填入bTask,URL填入http://localhost:8080.在接下来的对话框中,确保选择的http://而不是https://,然后输入localhost:8080,单击“创建客户端ID”.

现在你会看到在一组值“Client ID for web applications”,在这个上面写着“Client ID”非常重要,请做好记录

你现在应该有一个API key和Client ID,有了这个,在浏览器端,我们就可以通过使用OAuth 2.0服务来访问Google’s APIs了—将不再需要编写我们自己的服务器端代码来验证用户身份。

接下来操作

如果你想看看第1部分中的源代码,您可以使用Git来获取从上周的确切版本:

git clone git@github.com:alexyoung/dailyjs-backbone-tutorial.git
cd dailyjs-backbone-tutorial
git reset --hard 2a8517e

引入需要的库

在进行之前,需下载下面的库到app/js/lib/:

打开app/js/main.js文件编辑requirejs.config下得shim属性去加载Underscore.js和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();
});

这看起来不可思议,但请记住,我们正在使用RequireJS来加载脚本模块。再RequireJS中“shim”允许依赖非AMD标准实现的库

加载Tasks API

以下是使用Google Tasks API的基本模式:

  1. 加载Google API客户端库https://apis.google.com/js/client.js
  2. 执行gapi.client.load初始化
  3. 给gapi.client.setApiKey()设置API key

实现这一点,你还需要个地方放必要的凭证。新建文件app/js/config.js,添加API key和Client ID:

define([], function() {
  var config = {};
  config.apiKey = 'your API key';
  config.scopes = 'https://www.googleapis.com/auth/tasks https://www.googleapis.com/auth/userinfo.profile';
  config.clientId = 'your client ID';
  return config;
});

这个文件可以通过我们的定制Google Tasks API/Backbone.sync实现加载。

现在我们新建app/js/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;
});

这个骨架模块实现了我们的Google Tasks API加载和Backbone.sync实例的整体设计,ApiManager是一个标准的构造函数,它继承自Underscore.js的Backbone.Events。这段代码是异步实现,不会阻塞后面事件的处理。

我们使用RequireJS加载了Google’s JavaScript的loadGapi方法.一旦全局对象gapi被发现,它会通过调用init方法进行配置的其余部分:

ApiManager.prototype.loadGapi = function() {
  var self = this;

  // Don't load gapi if it's already present
  if (typeof gapi !== 'undefined') {
    return this.init();
  }

  require(['https://apis.google.com/js/client.js?onload=define'], function() {
    // Poll until gapi is ready
    function checkGAPI() {
      if (gapi && gapi.client) {
        self.init();
      } else {
        setTimeout(checkGAPI, 100);
      }
    }

    checkGAPI();
  });
});

所有的init方法需要做的是加载执行Tasks API的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();
};

这个文件依赖config变量,因为它包含Google’s API所需的凭据。

加载API Manager

打开app/js/app.js文件,添加依赖模块gapi,实例化ApiManager:

define([
  'gapi'
],

function(ApiManager) {
  var App = function() {
    this.connectGapi();
  };

  App.prototype = {
    connectGapi: function() {
      this.apiManager = new ApiManager();
    }
  };

  return App;
});

如果您需要检查这个工程通过能否运行测试,修改test/setup.js文件,将gapi作为一个全局变量:

var assert = chai.assert;

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

不过,我不打算在测试过程中远程加载API - 这可能会又问题.这部分我们放到下一个部分。

结果

enter image description here 运行这个应用程序打开脚本控制台,应该会有一个gapi全局变量.用RequireJS和Backbone.js来使用Google’s APIs看起来好像又很多工作,但大多数是改改配置文件,一旦我们完成了这些工作,我就可以更加专注于应用设计和开发上。

完整的源代码

Commit 9d09a6

参考资料

Using OAuth 2.0 for Client-side Applications