Part 2: Google's APIs 和 RequireJS

z.w發表於2014-12-04

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

相關文章