Apps Script API で関数を実行する

Google Apps Script API は、 scripts.run メソッド リモートから特定の Apps Script 関数を実行します。この方法を使用できます 呼び出し元アプリケーションで、スクリプト プロジェクトのいずれかで関数を実行する レスポンスを受信します。

要件

呼び出し元のアプリケーションで scripts.run メソッドを呼び出します。必要なこと:

  • スクリプト プロジェクトを API 実行可能ファイルとしてデプロイします。Google Chat では 必要に応じてプロジェクトのデプロイ、デプロイ解除、再デプロイを行います。

  • 適切なスコープの OAuth トークンを実行用に指定します。 この OAuth トークンはすべてのスコープを網羅する必要があります 使用されるものだけではなく、スクリプトが使用します。詳しくは、 認可スコープの完全なリスト を渡しています。

  • スクリプトと呼び出し元アプリケーションの OAuth2 クライアントが共通の Google Cloud プロジェクトを共有している。 Cloud プロジェクトは標準の Cloud プロジェクトである必要があります。 Apps Script プロジェクト用に作成されたデフォルトのプロジェクトだけでは不十分です。新しい標準 Cloud プロジェクトまたは既存の標準プロジェクトを使用できます。

  • Google Apps Script API を有効にする 権限があります。

で確認できます。

scripts.run メソッド

scripts.run メソッドを実行するにはキー識別情報が必要です。

また、開発モードで実行するようにスクリプトを構成することもできます。 このモードは、最後に保存されたスクリプト プロジェクトのバージョンで実行されます。 最新のデプロイバージョンではなくこれを行うには、 devMode ブール値の リクエスト本文 宛先: true。開発モードでスクリプトを実行できるのは、そのスクリプトのオーナーのみです。

パラメータのデータ型を処理する

Apps Script API の使用 scripts.run メソッド 通常は関数パラメータとして Apps Script にデータを送信し、 データを関数の戻り値として返すことができます。この API は 基本型(文字列、配列、オブジェクト、数値、ブール値)を持つことができます。これらの JavaScript の基本的な型に似ています。より複雑 Document などの Apps Script オブジェクト または Sheet を API でスクリプト プロジェクトから読み取ることができます。

呼び出し側のアプリケーションが、 Java では、パラメータを汎用オブジェクトのリストまたは配列として渡します。 対応しています。多くの場合、単純なルールを適用する 自動的に変換されます。たとえば、1 対 1 の パラメータとして、Java の DoubleIntegerLong オブジェクトを指定できます。 パラメータ化できます。

API が関数のレスポンスを返すときに、多くの場合、 正しい型に変換する必要があります。以下に例を示します。 Java ベースの例:

  • API から Java アプリケーションに返される数値は、 java.math.BigDecimal オブジェクト。このオブジェクトは、必要に応じて 必要に応じて Doubles 型または int 型を使用します。
  • Apps Script 関数が文字列の配列を返す場合、 レスポンスを List<String> オブジェクトにキャストします。

    List<String> mylist = (List<String>)(op.getResponse().get("result"));
    
  • Bytes の配列を返す場合は、 Apps Script 関数内で配列を base64 文字列としてエンコードし、 代わりにその文字列を返します。

    return Utilities.base64Encode(myByteArray); // returns a String.
    

以下のコードサンプルの例では、 API レスポンスを解釈する方法を学びます。

一般的な手順

ここでは、Apps Script API の一般的な使用手順について説明します。 Apps Script 関数を実行します。

ステップ 1: 共通の Cloud プロジェクトを設定する

スクリプトと呼び出し元アプリケーションの両方が同じ できます。この Cloud プロジェクトは、既存のプロジェクトか、 新しいプロジェクトを作成することをおすすめします。クラウド プロジェクトを用意したら、 使用するスクリプト プロジェクトを切り替える必要があります。

ステップ 2: API 実行可能ファイルとしてスクリプトをデプロイする

  1. 使用する関数がある Apps Script プロジェクトを開きます。
  2. 右上の [デプロイ] &gt; [新しいデプロイ] をクリックします。
  3. 表示されたダイアログで、[デプロイタイプを有効にする] をクリックします。 &gt; [API Executable] を選択します。
  4. [アクセスできるユーザー]にあるプルダウン メニューで、 Apps Script API を使用してスクリプトの関数を呼び出すことができます。
  5. [デプロイ] をクリックします。

ステップ 3: 呼び出し元アプリケーションを構成する

呼び出し元のアプリケーションで Apps Script API を有効にして、OAuth を確立する必要がある 認証情報を使わずに済みますCloud プロジェクトへのアクセス権が必要です。 できます。

  1. 呼び出し元のアプリケーションとスクリプトが使用する Cloud プロジェクトを構成します。 手順は次のとおりです。 <ph type="x-smartling-placeholder">
      </ph>
    1. Cloud プロジェクトで Apps Script API を有効にします
    2. OAuth 同意画面を構成する
    3. OAuth 認証情報を作成する
  2. スクリプト プロジェクトを開き、左側の [概要] をクリックします。
  3. [プロジェクト OAuth スコープ] で、プロジェクト 指定します。
  4. 呼び出し元のアプリケーション コードで、OAuth アクセス トークンのスクリプトを生成します。 あります。これは API 自体が使用するトークンではなく、 必要な引数を指定します。まず、 Cloud プロジェクトのクライアント ID と記録したスクリプト スコープ。

    Google クライアント ライブラリを使用すると、 このトークンの作成とアプリケーションの OAuth の処理を支援します。 通常は、代わりに上位レベルの「認証情報」を構築できます。オブジェクト スクリプトスコープを使用します詳しくは、 例については、Apps Script API クイックスタート 認証情報オブジェクトを構築する方法です。

ステップ 4: script.run リクエストを行う

呼び出し元アプリケーションの構成が完了したら、 scripts.run 呼び出し。API ごとに コールは以下の手順で構成されます。

  1. API リクエストを作成する スクリプト ID、関数名、必要なすべての あります。
  2. scripts.run を作成する 使用してスクリプトの OAuth トークンを呼び出し、 ヘッダー(基本的な POST リクエストを使用する場合)、または認証情報オブジェクトを使用する スコープを使用してビルドします。
  3. スクリプトの実行が完了するまで待ちます。スクリプトの実行には最大で 6 分間かかるので、アプリケーションはこれを考慮する必要があります。
  4. 終了時にスクリプト関数は値を返し、API はその値を 値がサポートされているタイプであれば、アプリケーションに返されます。

script.run API 呼び出しの例をご覧ください。 ご覧ください

API リクエストの例

次の例は、Google Cloud コンソールで Apps Script API の実行リクエストを行う方法を示しています。 さまざまな言語のリストを出力する Apps Script 関数を呼び出して、 ルート ディレクトリに保存されます。Apps Script プロジェクトのスクリプト ID 指定する場合は、関数を ENTER_YOUR_SCRIPT_ID_HERE。この例は、 対応する Google API クライアント ライブラリ 対応しています。

ターゲット スクリプト

このスクリプトの関数は、Drive API を使用します。

次の場所で Drive API を有効にする必要があります。 プロジェクトを作成します。

さらに、呼び出し元アプリケーションは、 次のドライブ スコープ:

  • https://www.googleapis.com/auth/drive

ここのサンプル アプリケーションでは、Google クライアント ライブラリを使用して、 認証情報オブジェクトを暗号化します。

/**
 * Return the set of folder names contained in the user's root folder as an
 * object (with folder IDs as keys).
 * @return {Object} A set of folder names keyed by folder ID.
 */
function getFoldersUnderRoot() {
  const root = DriveApp.getRootFolder();
  const folders = root.getFolders();
  const folderSet = {};
  while (folders.hasNext()) {
    const folder = folders.next();
    folderSet[folder.getId()] = folder.getName();
  }
  return folderSet;
}

Java


/**
 * Create a HttpRequestInitializer from the given one, except set
 * the HTTP read timeout to be longer than the default (to allow
 * called scripts time to execute).
 *
 * @param {HttpRequestInitializer} requestInitializer the initializer
 *                                 to copy and adjust; typically a Credential object.
 * @return an initializer with an extended read timeout.
 */
private static HttpRequestInitializer setHttpTimeout(
    final HttpRequestInitializer requestInitializer) {
  return new HttpRequestInitializer() {
    @Override
    public void initialize(HttpRequest httpRequest) throws IOException {
      requestInitializer.initialize(httpRequest);
      // This allows the API to call (and avoid timing out on)
      // functions that take up to 6 minutes to complete (the maximum
      // allowed script run time), plus a little overhead.
      httpRequest.setReadTimeout(380000);
    }
  };
}

/**
 * Build and return an authorized Script client service.
 *
 * @param {Credential} credential an authorized Credential object
 * @return an authorized Script client service
 */
public static Script getScriptService() throws IOException {
  Credential credential = authorize();
  return new Script.Builder(
      HTTP_TRANSPORT, JSON_FACTORY, setHttpTimeout(credential))
      .setApplicationName(APPLICATION_NAME)
      .build();
}

/**
 * Interpret an error response returned by the API and return a String
 * summary.
 *
 * @param {Operation} op the Operation returning an error response
 * @return summary of error response, or null if Operation returned no
 * error
 */
public static String getScriptError(Operation op) {
  if (op.getError() == null) {
    return null;
  }

  // Extract the first (and only) set of error details and cast as a Map.
  // The values of this map are the script's 'errorMessage' and
  // 'errorType', and an array of stack trace elements (which also need to
  // be cast as Maps).
  Map<String, Object> detail = op.getError().getDetails().get(0);
  List<Map<String, Object>> stacktrace =
      (List<Map<String, Object>>) detail.get("scriptStackTraceElements");

  java.lang.StringBuilder sb =
      new StringBuilder("\nScript error message: ");
  sb.append(detail.get("errorMessage"));
  sb.append("\nScript error type: ");
  sb.append(detail.get("errorType"));

  if (stacktrace != null) {
    // There may not be a stacktrace if the script didn't start
    // executing.
    sb.append("\nScript error stacktrace:");
    for (Map<String, Object> elem : stacktrace) {
      sb.append("\n  ");
      sb.append(elem.get("function"));
      sb.append(":");
      sb.append(elem.get("lineNumber"));
    }
  }
  sb.append("\n");
  return sb.toString();
}

public static void main(String[] args) throws IOException {
  // ID of the script to call. Acquire this from the Apps Script editor,
  // under Publish > Deploy as API executable.
  String scriptId = "ENTER_YOUR_SCRIPT_ID_HERE";
  Script service = getScriptService();

  // Create an execution request object.
  ExecutionRequest request = new ExecutionRequest()
      .setFunction("getFoldersUnderRoot");

  try {
    // Make the API request.
    Operation op =
        service.scripts().run(scriptId, request).execute();

    // Print results of request.
    if (op.getError() != null) {
      // The API executed, but the script returned an error.
      System.out.println(getScriptError(op));
    } else {
      // The result provided by the API needs to be cast into
      // the correct type, based upon what types the Apps
      // Script function returns. Here, the function returns
      // an Apps Script Object with String keys and values,
      // so must be cast into a Java Map (folderSet).
      Map<String, String> folderSet =
          (Map<String, String>) (op.getResponse().get("result"));
      if (folderSet.size() == 0) {
        System.out.println("No folders returned!");
      } else {
        System.out.println("Folders under your root folder:");
        for (String id : folderSet.keySet()) {
          System.out.printf(
              "\t%s (%s)\n", folderSet.get(id), id);
        }
      }
    }
  } catch (GoogleJsonResponseException e) {
    // The API encountered a problem before the script was called.
    e.printStackTrace(System.out);
  }
}

JavaScript

/**
 * Load the API and make an API call.  Display the results on the screen.
 */
function callScriptFunction() {
  const scriptId = '<ENTER_YOUR_SCRIPT_ID_HERE>';

  // Call the Apps Script API run method
  //   'scriptId' is the URL parameter that states what script to run
  //   'resource' describes the run request body (with the function name
  //              to execute)
  try {
    gapi.client.script.scripts.run({
      'scriptId': scriptId,
      'resource': {
        'function': 'getFoldersUnderRoot',
      },
    }).then(function(resp) {
      const result = resp.result;
      if (result.error && result.error.status) {
        // The API encountered a problem before the script
        // started executing.
        appendPre('Error calling API:');
        appendPre(JSON.stringify(result, null, 2));
      } else if (result.error) {
        // The API executed, but the script returned an error.

        // Extract the first (and only) set of error details.
        // The values of this object are the script's 'errorMessage' and
        // 'errorType', and an array of stack trace elements.
        const error = result.error.details[0];
        appendPre('Script error message: ' + error.errorMessage);

        if (error.scriptStackTraceElements) {
          // There may not be a stacktrace if the script didn't start
          // executing.
          appendPre('Script error stacktrace:');
          for (let i = 0; i < error.scriptStackTraceElements.length; i++) {
            const trace = error.scriptStackTraceElements[i];
            appendPre('\t' + trace.function + ':' + trace.lineNumber);
          }
        }
      } else {
        // The structure of the result will depend upon what the Apps
        // Script function returns. Here, the function returns an Apps
        // Script Object with String keys and values, and so the result
        // is treated as a JavaScript object (folderSet).

        const folderSet = result.response.result;
        if (Object.keys(folderSet).length == 0) {
          appendPre('No folders returned!');
        } else {
          appendPre('Folders under your root folder:');
          Object.keys(folderSet).forEach(function(id) {
            appendPre('\t' + folderSet[id] + ' (' + id + ')');
          });
        }
      }
    });
  } catch (err) {
    document.getElementById('content').innerText = err.message;
    return;
  }
}

Node.js

/**
 * Call an Apps Script function to list the folders in the user's root Drive
 * folder.
 *
 */
async function callAppsScript() {
  const scriptId = '1xGOh6wCm7hlIVSVPKm0y_dL-YqetspS5DEVmMzaxd_6AAvI-_u8DSgBT';

  const {GoogleAuth} = require('google-auth-library');
  const {google} = require('googleapis');

  // Get credentials and build service
  // TODO (developer) - Use appropriate auth mechanism for your app
  const auth = new GoogleAuth({
    scopes: 'https://www.googleapis.com/auth/drive',
  });
  const script = google.script({version: 'v1', auth});

  try {
    // Make the API request. The request object is included here as 'resource'.
    const resp = await script.scripts.run({
      auth: auth,
      resource: {
        function: 'getFoldersUnderRoot',
      },
      scriptId: scriptId,
    });
    if (resp.error) {
      // The API executed, but the script returned an error.

      // Extract the first (and only) set of error details. The values of this
      // object are the script's 'errorMessage' and 'errorType', and an array
      // of stack trace elements.
      const error = resp.error.details[0];
      console.log('Script error message: ' + error.errorMessage);
      console.log('Script error stacktrace:');

      if (error.scriptStackTraceElements) {
        // There may not be a stacktrace if the script didn't start executing.
        for (let i = 0; i < error.scriptStackTraceElements.length; i++) {
          const trace = error.scriptStackTraceElements[i];
          console.log('\t%s: %s', trace.function, trace.lineNumber);
        }
      }
    } else {
      // The structure of the result will depend upon what the Apps Script
      // function returns. Here, the function returns an Apps Script Object
      // with String keys and values, and so the result is treated as a
      // Node.js object (folderSet).
      const folderSet = resp.response.result;
      if (Object.keys(folderSet).length == 0) {
        console.log('No folders returned!');
      } else {
        console.log('Folders under your root folder:');
        Object.keys(folderSet).forEach(function(id) {
          console.log('\t%s (%s)', folderSet[id], id);
        });
      }
    }
  } catch (err) {
    // TODO(developer) - Handle error
    throw err;
  }
}

Python

import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError


def main():
  """Runs the sample."""
  # pylint: disable=maybe-no-member
  script_id = "1VFBDoJFy6yb9z7-luOwRv3fCmeNOzILPnR4QVmR0bGJ7gQ3QMPpCW-yt"

  creds, _ = google.auth.default()
  service = build("script", "v1", credentials=creds)

  # Create an execution request object.
  request = {"function": "getFoldersUnderRoot"}

  try:
    # Make the API request.
    response = service.scripts().run(scriptId=script_id, body=request).execute()
    if "error" in response:
      # The API executed, but the script returned an error.
      # Extract the first (and only) set of error details. The values of
      # this object are the script's 'errorMessage' and 'errorType', and
      # a list of stack trace elements.
      error = response["error"]["details"][0]
      print(f"Script error message: {0}.{format(error['errorMessage'])}")

      if "scriptStackTraceElements" in error:
        # There may not be a stacktrace if the script didn't start
        # executing.
        print("Script error stacktrace:")
        for trace in error["scriptStackTraceElements"]:
          print(f"\t{0}: {1}.{format(trace['function'], trace['lineNumber'])}")
    else:
      # The structure of the result depends upon what the Apps Script
      # function returns. Here, the function returns an Apps Script
      # Object with String keys and values, and so the result is
      # treated as a Python dictionary (folder_set).
      folder_set = response["response"].get("result", {})
      if not folder_set:
        print("No folders returned!")
      else:
        print("Folders under your root folder:")
        for folder_id, folder in folder_set.items():
          print(f"\t{0} ({1}).{format(folder, folder_id)}")

  except HttpError as error:
    # The API encountered a problem before the script started executing.
    print(f"An error occurred: {error}")
    print(error.content)


if __name__ == "__main__":
  main()

制限事項

Apps Script API にはいくつかの制限があります。

  1. 共通の Cloud プロジェクト。呼び出されるスクリプトと、 Cloud プロジェクトを共有する必要があります。Cloud プロジェクトは 標準 Cloud プロジェクト Apps Script プロジェクト用に作成されたデフォルトのプロジェクトだけでは不十分です。「 新しいプロジェクトまたは既存のプロジェクトになります。

  2. 基本的なパラメータと戻り値の型。API が渡すことも、返すこともできない Apps Script 固有のオブジェクト(Documentsblob カレンダードライブのファイルなど)を 説明します。基本的な型(文字列、配列、オブジェクト、数値、 ブール値を渡して返すことができます。

  3. OAuth スコープ。API で実行できるスクリプトは、少なくとも 必要ありません。つまり、API を使用してスクリプトを呼び出すことはできません。 認証を必要としない場合があります。

  4. トリガーなし。この API では Apps Script を作成できません。 トリガー