0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GASの関数を外部から実行する

Posted at

はじめに

GASはスプレッドシートなどのGoogleWorkpaceをシームレスに操作できて便利でが、通常はGoogleWorkspaceアプリ内でしか呼び出せません。しかし、これはGoogleも織り込み済みのようで、GASには関数を 実行可能API として外部に公開する機能があり、実行可能APIを使えば外部サーバでホスティングされているWebアプリからも間接的にGoogleWorkspaceアプリを操作できるようになります。

サンプルアプリの概要

この記事ではローカル端末のブラウザからGASの関数を実行するサンプルアプリを作ります。

image.png

作業手順

GASの関数を外部から実行する手順を見ていきましょう。

少し長いですが、お付き合いください。

GAS関数の作成

実行可能APIとしてデプロイして外部から実行できるようにするGASの関数を作成します。

  1. 任意のフォルダにGASのプロジェクトを作成

    image.png

  2. コード.gsを以下のように編集

    function getFilesInFolder(folderId) {
       let folder = DriveApp.getFolderById(folderId);
       let files = folder.getFiles();
       let fileNameList = [];
       while (files.hasNext()) {
          let file = files.next();
          fileNameList.push(file.getName());
       }
       return fileNameList;
    }
    
    function test_getFileInFolder() {
       let res = getFilesInFolder("フォルダID");
       Logger.log(res);
    }
    
    📝フォルダIDの確認方法

    フォルダIDとは、Googleドライブ内のフォルダを識別するためのユニークな文字列です。このフォルダIDはGoogleドライブのURLの一部として表示されており、フォルダのURLの「folders/」以降の文字列を見れば確認できます。

    [例] URL = https://drive.google.com/drive/folders/1A2B3C4D5E6F
      ⇒ フォルダID = 1A2B3C4D5E6F


  3. 「フォルダID」を任意のフォルダIDに置き換えて test_getFileInFolder を実行

    image.png
    ※ 初回実行時は権限の確認を求められます

GCPプロジェクトの設定

プロジェクトの作成

認証機能を使うためのGoogle Cloudプロジェクトを作成します。

  1. Google Cloudのウェルカムページを開く

  2. 画面左上の「プロジェクトの選択」をクリック

    image.png

  3. 画面右上の「新しいプロジェクト」を選択

    image.png

  4. 任意のプロジェクト名を設定して「作成」をクリック

    image.png

APIの有効化

サンプルアプリで使用するAPIを有効化します。

  1. 画面左上のメニューボタンからサイドバーを展開して「APIとサービス」→「ライブラリ」と選択

    image.png

  2. APIライブラリページが開いたら上部中央の検索欄で「Google Drive API」を検索

    image.png

  3. 検索結果の中から「Google Drive API」を選択

    image.png

  4. 製品の詳細を確認して「有効にする」をクリック

    image.png

  5. 同様の手順でApps Script APIも有効化

    image.png

OAuth認証画面の作成

OAuth同意画面を作成します。

ちなみに、OAuth同意画面はGoogle Drive APIなどのユーザの同意が必要なAPIを使う場合にユーザへ権限の確認を求めるために使用します。

  1. 画面左上のメニューボタンからサイドバーを展開して「APIとサービス」→「OAuth同意画面」と選択

    image.png

  2. ユーザタイプの選択では「External(外部)」を選択して「作成」をクリック

    image.png

  3. アプリの情報を求められたら次の項目を入力して「保存して次へ」をクリック

    • アプリ名:OAuth同意画面に表示されるアプリの名称
    • ユーザーサポートメール:OAuth同意画面に表示される問い合わせ先メールアドレス
    • デベロッパーの連絡先情報:Googleからの通知を受け取るメールアドレス

    image.png
    image.png

  4. 「スコープを追加または削除」をクリックして「フィルタ」欄に「 https://www.googleapis.com/auth/drive.readonly 」入力し、必要なスコープを選択したら「更新」をクリックして「保存して次へ」を選択

    image.png
    image.png
    ※ 実行可能APIに必要なスコープはApps Scriptプロジェクトの「概要」画面下部の「プロジェクトの OAuth スコープ」欄で確認できます

  5. テストユーザの追加画面で「ADD USERS」をクリックしてテストを実施するユーザのメールアドレスを入力し、「追加」をクリックして「保存して次へ」を選択

    image.png

認証情報の作成

サンプルアプリ内でユーザを認証するための情報を作成します。

  1. サイドバーの「認証情報」から「認証情報を作成」→「OAuthクライアントID」と選択

    image.png

  2. 「アプリケーションの種類」を「ウェブアプリケーション」に設定

    image.png

  3. 「承認済みのJavaScript生成元」欄に「 http://localhost:9999 」と入力して「作成」をクリック

    image.png

    📝URIの設定について

    「認証済みのJavaScript生成元」のURLはドメインを設定する必要があります。
    そのため、今回は http://localhost を設定しましたが、localhostではどの端末からでも接続できてしまうので、このサンプルではポート番号(:9999)を使用して接続経路を絞り込んでいます。

    ポート番号は65535までの番号を指定できるので、不安がある方はポート番号を変更してテストしてみてください。


  4. 「クライアントID」が表示されたらコピーして「OK」をクリック

    image.png

APIキーの作成

  1. 「認証情報」画面から「認証情報を作成」→「APIキー」と順に選択

    image.png

  2. APIキーが表示されたらコピーして「閉じる」をクリック

    image.png

GASのプロジェクトの設定

GASとGCPを紐づける

  1. 画面上部ののプロジェクト名を確認して左上メニューボタンからGCPプロジェクトのダッシュボードを開く

    image.png

  2. GCPプロジェクトのダッシュボードで「プロジェクト番号」をコピー

    image.png

  3. GASのプロジェクトの設定画面を開く

    image.png

  4. GASのプロジェクトの設定画面のGoogle Cloud Platform (GCP) プロジェクト欄の「プロジェクトを変更」ボタンをクリック

    image.png

  5. プロジェクト番号を入力して「プロジェクトを設定」をクリック

    image.png

実行可能APIをデプロイする

  1. GASのプロジェクト画面右上の「デプロイ」から「新しいデプロイ」を選択

    image.png

  2. 新しいデプロイの設定画面でデプロイの種類を「実行可能API」に設定

    image.png

  3. デプロイの詳細を以下のように入力して「デプロイ」をクリック

    image.png

  4. デプロイが完了したら「デプロイID」をコピーして「閉じる」を選択

    image.png
    (※このデプロイIDは「サンプルスクリプトの作成」で使います)

サンプルアプリの作成

index.htmlの作成

  1. 任意の作業フォルダにindex.htmlを作成

  2. index.htmlの内容を以下のように編集

    <!DOCTYPE html>
    <html>
    <head>
       <title>実行可能APIクイックスタート</title>
       <meta charset="utf-8" />
       <style>
          body {
             background-color: black;
             color: white;
          }
       </style>
    </head>
    <body>
       <h1>実行可能APIテスト</h1>
    
       <button id="run_button" onclick="handleRunClick()" hidden>実行</button>
       <button id="reset_button" onclick="handleResetClick()" hidden>リセット</button>
    
       <ol id="content"></ol>
    
       <script type="text/javascript">
    
          const CLIENT_ID = "クライアントID"; // TODO: GCPで取得したクライアントIDを貼付
          const API_KEY = "APIキー"; // TODO: GCPで取得したAPIキーを貼付
          const SCRIPT_ID = 'デプロイID'; // TODO: GASで取得したデプロイIDを張付
          const FOLDER_ID = "フォルダID"; // TODO: GoogleドライブのフォルダIDを貼付
          const SCOPES = "https://www.googleapis.com/auth/drive";
    
          let tokenClient;
          let gapiInited = false;
          let gisInited = false;
    
          // Google APIクライアントライブラリの初期化
          function gapiLoaded() {
             gapi.load("client", async () => {
                await gapi.client.init({
                   apiKey: API_KEY,
                   discoveryDocs: ["https://script.googleapis.com/$discovery/rest?version=v1"],
                });
                gapiInited = true;
                maybeEnableButtons();
             });
          }
          
          // Google Identity Serviceクライアントライブラリの初期化
          function gisLoaded() {
             tokenClient = google.accounts.oauth2.initTokenClient({
                   client_id: CLIENT_ID,
                   scope: SCOPES,
                   callback: "",
             });
             gisInited = true;
             maybeEnableButtons();
          }
    
          // Google APIライブラリとGISライブラリの初期化が両方完了したら認証ボタンを表示
          function maybeEnableButtons() {
             if (gapiInited && gisInited) {
                   document.getElementById("run_button").hidden = false;
             }
          }
    
          // 実行ボタンがクリックされた時の処理
          function handleRunClick() {
             if (gapi.client.getToken() === null) {
                // トークンを取得していない場合の処理
                tokenClient.callback = async (resp) => {
                      if (resp.error !== undefined) throw (resp);
                      document.getElementById("reset_button").hidden = false;
                      document.getElementById("run_button").innerText = "更新";
                      await callScriptFunction();
                };
                tokenClient.requestAccessToken({
                   prompt: "consent"
                });
             } else {
                // トークを取得している場合の処理
                tokenClient.callback = async (resp) => {
                      if (resp.error !== undefined) throw (resp);
                      document.getElementById("content").innerHTML = "";
                      await callScriptFunction();
                };
                tokenClient.requestAccessToken({
                   prompt: ""
                });
             }
          }
    
          // リセットボタンがクリックされた時の処理
          function handleResetClick() {
             const token = gapi.client.getToken();
             if (token !== null) {
                google.accounts.oauth2.revoke(token.access_token);
                gapi.client.setToken("");
                document.getElementById("content").innerHTML = "";
                document.getElementById("run_button").innerText = "実行";
                document.getElementById("reset_button").hidden = true;
             }
          }
    
          // 実行可能APIを呼び出す処理
          async function callScriptFunction() {
             try {
                gapi.client.script.scripts.run({
                   'scriptId': SCRIPT_ID,
                   'resource': {
                      'function': 'getFilesInFolder',
                      'parameters': [FOLDER_ID],
                   },
                }).then(function(resp) {
                   const result = resp.result;
                   if (result.error && result.error.status) {
                      // API実行前にエラーになった場合の処理
                      console.error('Error calling API:');
                      console.error(JSON.stringify(result, null, 2));
                   } else if (result.error) {
                      // API実行中にエラーになった場合の処理
                      const error = result.error.details[0];
                      console.error('Script error message: ' + error.errorMessage);
                      if (error.scriptStackTraceElements) {
                         console.error('Script error stacktrace:');
                         for (let i = 0; i < error.scriptStackTraceElements.length; i++) {
                            const trace = error.scriptStackTraceElements[i];
                            console.error('\t' + trace.function + ':' + trace.lineNumber);
                         }
                      }
                   } else {
                      // 実行可能APIからのレスポンスを処理
                      const fileList = result.response.result;
                      if (fileList.length == 0) {
                         console.warn('ファイルが見つかりませんでした');
                      } else {
                         fileList.forEach((file) => {
                            li = document.createElement("li");
                            li.textContent = file;
                            document.getElementById('content').appendChild(li);
                         });
                      }
                   }
                });
             } catch (err) {
                document.getElementById('content').innerText = err.message;
                return;
             }
          }
       </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. index.htmlが置かれているディレクトリで下記のコマンドを実行

    npm install http-server
    

  2. 次のコマンドでローカルサーバを起動

    npx http-server -p 9999
    

動作確認

  1. ブラウザで http://localhost:9999 にアクセス

    image.png

  2. 「実行」ボタンをクリックするとOAuth認証画面が開くので実行するアカウントを選択する

    image.png

  3. 「このアプリはGoogleで確認されていません」などのメッセージが出ますが「続行」を選択

    image.png

  4. スコープの利用について同意を求められたら内容を確認して「続行」を選択

    image.png

  5. 少し待って下図のようにファイル名の一覧が表示されれば成功です!!

    image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?