JavaScript 快速入門導覽課程

快速入門導覽課程說明如何設定及執行會呼叫 Google Workspace API

Google Workspace 快速入門導覽課程會使用 API 用戶端程式庫 驗證和授權流程的詳細資訊建議做法 您為自己的應用程式使用用戶端程式庫本快速入門導覽課程會使用 適合用於測試的簡易驗證方式 環境。在正式環境中,建議您瞭解 驗證與授權選擇存取認證 挑選適合您應用程式的語言版本

建立 JavaScript 網頁應用程式,向 Google Drive Activity API 提出要求。

目標

  • 設定環境。
  • 設定範例。
  • 執行範例。

必要條件

  • Google 帳戶

設定環境

如要完成本快速入門導覽課程,請設定環境。

啟用 API

您必須先在 Google Cloud 專案中啟用這些 Google API,才能使用這些 API。 您可以在單一 Google Cloud 專案中啟用一或多個 API。
  • 在 Google Cloud 控制台中,啟用 Google Drive Activity API。

    啟用 API

如要使用新的 Google Cloud 專案完成本快速入門導覽課程,請設定 將自己新增為測試使用者。如果您已 為 Cloud 專案完成這個步驟,請直接跳到下一節。

  1. 在 Google Cloud 控制台中,前往「選單」圖示 > API 與服務 >「OAuth 同意畫面」

    前往 OAuth 同意畫面

  2. 在「使用者類型」部分選取「內部」,然後按一下「建立」
  3. 填寫應用程式註冊表單,然後按一下「Save and Continue」
  4. 您現在可以略過新增範圍的步驟,然後按一下「儲存並繼續」。 日後您可以製作並使用應用程式 Google Workspace 機構,您必須將「使用者類型」變更為「外部」, 新增應用程式所需的授權範圍。

  5. 查看應用程式註冊摘要。如要修改資訊,請按一下「編輯」。如果應用程式 註冊看起來沒有問題,請按一下 [返回資訊主頁]

授權網頁應用程式的憑證

如要驗證使用者及存取應用程式中的使用者資料,您必須: 建立一或多個 OAuth 2.0 用戶端 ID。用戶端 ID 可用來識別 單一應用程式傳送至 Google 的 OAuth 伺服器。如果您的應用程式在多個平台上運作 您都必須為每個平台分別建立用戶端 ID。
  1. 在 Google Cloud 控制台中,依序點選「選單」圖示 > 「API 與」「服務」 >「憑證」

    前往「憑證」

  2. 依序點選「建立憑證」>「OAuth 用戶端 ID」
  3. 依序點選「應用程式類型」>「網頁應用程式」
  4. 在「名稱」欄位中輸入憑證的名稱。這個名稱只會顯示在 Google Cloud 控制台中。
  5. 新增與應用程式相關的已授權 URI:
    • 用戶端應用程式 (JavaScript):按一下「授權的 JavaScript 來源」下方的「新增 URI」。然後輸入瀏覽器要求的 URI。可識別應用程式可以從哪些網域傳送 API 要求至 OAuth 2.0 伺服器。
    • 伺服器端應用程式 (Java、Python 等):按一下「已授權的重新導向 URI」下方的「新增 URI」。然後輸入端點 URI,讓 OAuth 2.0 伺服器傳送回應。
  6. 點選「建立」。系統隨即會顯示已建立 OAuth 用戶端的畫面,並顯示您的新用戶端 ID 和用戶端密鑰。

    記下用戶端 ID。用戶端密碼不適用於網頁應用程式,

  7. 按一下「OK」(確定)。新建立的憑證會顯示在「OAuth 2.0 用戶端 ID」之下。

請記下這些憑證,因為本快速入門導覽課程稍後會用到。

建立 API 金鑰

  1. 在 Google Cloud 控制台中,前往「選單」圖示 > API 與服務 >「憑證」

    前往「憑證」

  2. 按一下「建立憑證」> API 金鑰
  3. 系統會顯示您新的 API 金鑰。
    • 按一下「複製」圖示 複製 API 金鑰,以便用於應用程式的程式碼中。API 金鑰也可能是 列在「API 金鑰」部分專案憑證
    • 按一下「限制金鑰」,即可更新進階設定和限制用途 您的 API 金鑰詳情請參閱「套用 API 金鑰限制」一節。

設定範例

  1. 在工作目錄中,建立名為 index.html 的檔案。
  2. index.html 檔案中,貼上下列程式碼:

    drive/activity-v2/index.html
    <!DOCTYPE html>
    <html>
      <head>
        <title>Drive Activity API Quickstart</title>
        <meta charset="utf-8" />
      </head>
      <body>
        <p>Drive Activity API Quickstart</p>
    
        <!--Add buttons to initiate auth sequence and sign out-->
        <button id="authorize_button" onclick="handleAuthClick()">Authorize</button>
        <button id="signout_button" onclick="handleSignoutClick()">Sign Out</button>
    
        <pre id="content" style="white-space: pre-wrap;"></pre>
    
        <script type="text/javascript">
          /* exported gapiLoaded */
          /* exported gisLoaded */
          /* exported handleAuthClick */
          /* exported handleSignoutClick */
    
          // TODO(developer): Set to client ID and API key from the Developer Console
          const CLIENT_ID = '<YOUR_CLIENT_ID>';
          const API_KEY = '<YOUR_API_KEY>';
    
          // Discovery doc URL for APIs used by the quickstart
          const DISCOVERY_DOC = 'https://www.googleapis.com/discovery/v1/apis/driveactivity/v2/rest';
    
          // Authorization scopes required by the API; multiple scopes can be
          // included, separated by spaces.
          const SCOPES = 'https://www.googleapis.com/auth/drive.activity.readonly';
    
          let tokenClient;
          let gapiInited = false;
          let gisInited = false;
    
          document.getElementById('authorize_button').style.visibility = 'hidden';
          document.getElementById('signout_button').style.visibility = 'hidden';
    
          /**
           * Callback after api.js is loaded.
           */
          function gapiLoaded() {
            gapi.load('client', initializeGapiClient);
          }
    
          /**
           * Callback after the API client is loaded. Loads the
           * discovery doc to initialize the API.
           */
          async function initializeGapiClient() {
            await gapi.client.init({
              apiKey: API_KEY,
              discoveryDocs: [DISCOVERY_DOC],
            });
            gapiInited = true;
            maybeEnableButtons();
          }
    
          /**
           * Callback after Google Identity Services are loaded.
           */
          function gisLoaded() {
            tokenClient = google.accounts.oauth2.initTokenClient({
              client_id: CLIENT_ID,
              scope: SCOPES,
              callback: '', // defined later
            });
            gisInited = true;
            maybeEnableButtons();
          }
    
          /**
           * Enables user interaction after all libraries are loaded.
           */
          function maybeEnableButtons() {
            if (gapiInited && gisInited) {
              document.getElementById('authorize_button').style.visibility = 'visible';
            }
          }
    
          /**
           *  Sign in the user upon button click.
           */
          function handleAuthClick() {
            tokenClient.callback = async (resp) => {
              if (resp.error !== undefined) {
                throw (resp);
              }
              document.getElementById('signout_button').style.visibility = 'visible';
              document.getElementById('authorize_button').innerText = 'Refresh';
              await listActivities();
            };
    
            if (gapi.client.getToken() === null) {
              // Prompt the user to select a Google Account and ask for consent to share their data
              // when establishing a new session.
              tokenClient.requestAccessToken({prompt: 'consent'});
            } else {
              // Skip display of account chooser and consent dialog for an existing session.
              tokenClient.requestAccessToken({prompt: ''});
            }
          }
    
          /**
           *  Sign out the user upon button click.
           */
          function handleSignoutClick() {
            const token = gapi.client.getToken();
            if (token !== null) {
              google.accounts.oauth2.revoke(token.access_token);
              gapi.client.setToken('');
              document.getElementById('content').innerText = '';
              document.getElementById('authorize_button').innerText = 'Authorize';
              document.getElementById('signout_button').style.visibility = 'hidden';
            }
          }
    
          /**
           * Print recent activity.
           */
          async function listActivities() {
            let response;
            try {
              response = await gapi.client.driveactivity.activity.query({
                'pageSize': 10,
              });
            } catch (err) {
              document.getElementById('content').innerText = err.message;
              return;
            }
    
            const activities = response.result.activities;
            if (!activities || activities.length == 0) {
              document.getElementById('content').innerText = 'No activities found.';
              return;
            }
            // Flatten to string to display
            const output = activities.reduce(
                (str, activity) => {
                  const time = getTimeInfo(activity);
                  const action = getActionInfo(activity['primaryActionDetail']);
                  const actors = activity.actors.map(getActorInfo);
                  const targets = activity.targets.map(getTargetInfo);
                  return `${str}${time}: ${truncated(actors)}, ${action}, ${truncated(targets)}\n`;
                },
                'Activities:\n');
            document.getElementById('content').innerText = output;
          }
    
          // Utility methods for formatting activity records
    
          /**
           * Returns a string representation of the first N elements in a list.
           * @param {string[]} array - Values to join
           * @param {number} limit - # of elements to show
           * @return {string} formatted string
           */
          function truncated(array, limit = 2) {
            const contents = array.slice(0, limit).join(', ');
            const more = array.length > limit ? ', ...' : '';
            return `[${contents}${more}]`;
          }
    
          /**
           * Returns the first found property name in an object.
           * @param {object} object - Object to search
           * @return {string} key name or 'unknown'
           */
          function getOneOf(object) {
            const props = Object.getOwnPropertyNames(object);
            if (props.length === 0) {
              return 'unknown';
            }
            return props[0];
          }
    
          /**
           * Returns a time associated with an activity.
           * @param {object} activity - Activity record
           * @return {string} Formatted timestamp
           */
          function getTimeInfo(activity) {
            if ('timestamp' in activity) {
              return activity.timestamp;
            }
            if ('timeRange' in activity) {
              return activity.timeRange.endTime;
            }
            return 'unknown';
          }
    
          /**
           * Returns the type of action.
           * @param {object} actionDetail
           * @return {string} Action type as string
           */
          function getActionInfo(actionDetail) {
            return getOneOf(actionDetail);
          }
    
          /**
           * Returns user information, or the type of user if not a known user.
           * @param {object} user - User record
           * @return {string} user type as string
           */
          function getUserInfo(user) {
            if ('knownUser' in user) {
              const knownUser = user['knownUser'];
              const isMe = knownUser['isCurrentUser'] || false;
              return isMe ? 'people/me' : knownUser['personName'];
            }
            return getOneOf(user);
          }
    
          /**
           * Returns actor information, or the type of actor if not a user.
           * @param {object} actor - Actor record
           * @return {string} actor type as string
           */
          function getActorInfo(actor) {
            if ('user' in actor) {
              return getUserInfo(actor['user']);
            }
            return getOneOf(actor);
          }
    
          /**
           * Returns the type of a target and an associated title.
           * @param {object} target - Activity target record
           * @return {string} target type as string
           */
          function getTargetInfo(target) {
            if ('driveItem' in target) {
              const title = target.driveItem.title || 'unknown';
              return `driveItem:"${title}"`;
            }
            if ('drive' in target) {
              const title = target.drive.title || 'unknown';
              return `drive:"${title}"`;
            }
            if ('fileComment' in target) {
              const parent = target.fileComment.parent || {};
              const title = parent.title || 'unknown';
              return `fileComment:"${title}"`;
            }
            return `${getOneOf(target)}:unknown`;
          }
        </script>
        <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoaded()"></script>
        <script async defer src="https://accounts.google.com/gsi/client" onload="gisLoaded()"></script>
      </body>
    </html>

    更改下列內容:

執行範例

  1. 在工作目錄中,安裝 http-server 套件:

    npm install http-server
    
  2. 在工作目錄中啟動網路伺服器:

    npx http-server -p 8000
    
  1. 透過瀏覽器前往 http://localhost:8000
  2. 系統會提示您授予存取權:
    1. 如果尚未登入 Google 帳戶,請在系統提示時登入。如果 您已登入多個帳戶,請選取一個用於授權的帳戶。
    2. 然後點選 [Accept]

您的 JavaScript 應用程式會執行並呼叫 Google Drive Activity API。

後續步驟