Executing Functions using the Apps Script API

The Apps Script API provides a scripts.run method that remotely executes a specified Apps Script function. You can use this method in a calling application to run a function in one of your script projects remotely and receive a response.

Requirements

You must satisfy the following requirements before a calling application can use the scripts.run method. You must:

  • Deploy the script project as an API executable. You can deploy, undeploy, and redeploy projects as needed. You can also deploy a specific version of a project. This is helpful if you want to have stable release while you continue to develop your application.

  • Provide a properly scoped OAuth token for the execution. This OAuth token must cover all the scopes used by the script, not just the ones used by the called function. See the full list of authorization scopes in the method reference.

  • Ensure that the script and the calling application share a common Cloud Platform project. Any one of these projects work: the default project created with the Apps Script project, a new Cloud Platform project, or an existing Cloud Platform project.

The scripts.run method

The scripts.run method requires key identifying information in order to run:

You can optionally configure your script to execute with these behaviors:

  • Run in development mode. This mode executes with the most recently saved version of the script project rather than the most recently deployed version. Do this by setting the devMode boolean in the request body to true. Only the owner of the script can execute it in development mode.
  • Include document context when calling scripts.run from an Android add-on. When you use scripts.run in an Android add-ons for Google Docs or Sheets, you can pass the document context to the called function. This allows the called function to operate directly on the originating Document or Sheet. Do this by setting the sessionState string in the request body as described in Using document context with the Apps Script API.

Handling parameter data types

Using the Apps Script API scripts.run method usually involves sending data to Apps Script as function parameters and getting data back as function return values. The API can only take and return values with basic types: strings, arrays, objects, numbers, and booleans. These are similar to the basic types in JavaScript. More complex Apps Script objects like Document or Sheet cannot be passed into or from the script project by the API.

When your calling application is written in a strongly-type language such as Java, it passes in parameters as a list or array of generic objects corresponding to these basic types. In many cases, you can apply simple type conversions automatically. For example, a function that takes a number parameter can be given a Java Double or Integer or Long object as a parameter without extra handling.

When the API returns the function response, you often need to cast the returned value to the correct type before it can be used. Here are some Java-based examples:

  • Numbers returned by the API to a Java application arrive as java.math.BigDecimal objects, and may need to be converted to Doubles or int types as needed.
  • If the Apps Script function returns an array of strings, a Java application casts the response into a List<String> object:

    List<String> mylist = (List<String>)(op.getResponse().get("result"));
    
  • If you are looking to return an array of Bytes, you may find it convenient to encode the array as a base64 String within the Apps Script function and return that String instead:

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

The example code samples below illustrate ways of interpreting the API response.

General procedure

The following describes the general procedure for using the Apps Script API to execute Apps Script functions:

Step 1: Deploy the script as an API executable

  1. Create or open an Apps Script project with the functions you want to use in the Apps Script editor.
  2. Deploy the script project for execution by selecting Publish > Deploy as API executable.
  3. In the Version drop-down menu, select a version of the script project that you want the API to execute. You can create a new version if needed.
  4. In the Who has access to the script drop-down menu, select the users who are allowed to call the script's functions using the Apps Script API. Options here include Only myself, members in your domain, or Anyone.
  5. Click Deploy. The new dialog that opens shows your script's ID, listed under Current API ID. Make note of this ID—you need to include it in any Apps Script API scripts.run requests your application makes. If you need to find it again later, select Publish > Deploy as API executable.

Step 2: Set up the common Cloud Platform project

Both your script and the calling application need to share the same Cloud Platform project. You can achieve this by doing one of the following:

  • Use the default Cloud Platform project that is attached to your script project to set up the calling application's OAuth credentials. You can access the script's Cloud Platform project by doing the following:
    1. Open your target Apps Script in the editor and select Resources > Cloud Platform project.
    2. In the dialog that opens, click on the blue link (that starts with your script's name) at the top to open the console project associated with your script.
  • Use an existing Cloud Platform project (or create a new one) for your calling application and switch the script project to use it.

You must have access to the Cloud Platform project to enable the API. This may not be the case if the script resides in Team Drive.

Step 3: Configure the calling application

The calling application must enable the Apps Script API and establish OAuth crendentials before it can be used.

  1. Enable the Google Apps Script API in the Cloud Platform project. You can find directions for doing this in the Apps Script API Java Quickstart.
  2. Create a valid Client ID and client secret for the application in the Cloud Platform project. This is also covered in the Apps Script API Java Quickstart.
  3. Open the script project in the Apps Script editor and select File > Project properties > Scopes. Record all the scopes that the script requires.
  4. In the calling application code, generate a script OAuth access token for the API call. This is not a token the API itself uses, but rather one the script requires when executing. It should be built using the Cloud Platform project client ID and the script scopes you recorded.

    The Google client libraries can greatly assist in building this token and handling OAuth for the application, usually allowing you to instead build a higher-level "credentials" object using the script scopes. See the Apps Script API quickstarts for examples of building a credentials object from a list of scopes.

Step 4: Make the script.run request

Once the calling application is configured, you can make scripts.run calls. Each API call consists of the following steps:

  1. Build an API request using the script ID, function name, and any required parameters.
  2. Make the scripts.run call and include the script OAuth token you built in the header (if using a basic POST request) or else use a crendentials object you built with the script scopes.
  3. Allow the script to finish executing. Scripts are allowed to take up to six minutes of execution time, so your application should allow for this.
  4. Upon finishing, the script function may return a value, which the API delivers back to the application if the value is a supported type.

You can find examples of script.run API calls below.

API request examples

The following examples show how to make an Apps Script API execution request in various languages, calling an Apps Script function to print out a list of folders in the user's root directory. The script ID of the Apps Script project containing the executed function must be specified where indicated with ENTER_YOUR_SCRIPT_ID_HERE. The examples rely on the Google API Client libraries for their respective languages.

Target Script

The function in this script requires the following Drive scope:

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

The calling applications use the Google client libraries to build credential objects for OAuth using this scope.

/**
 * 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() {
  var root = DriveApp.getRootFolder();
  var folders = root.getFolders();
  var folderSet = {};
  while (folders.hasNext()) {
    var folder = folders.next();
    folderSet[folder.getId()] = folder.getName();
  }
  return folderSet;
}

Android

/**
 * Call the API to run an Apps Script function that returns a list
 * of folders within the user's root directory on Drive.
 *
 * @return list of String folder names and their IDs
 * @throws IOException
 */
private List<String> getDataFromApi()
        throws IOException, GoogleAuthException {
    // 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";

    List<String> folderList = new ArrayList<String>();

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

    // Make the request.
    Operation op =
            mService.scripts().run(scriptId, request).execute();

    // Print results of request.
    if (op.getError() != null) {
        throw new IOException(getScriptError(op));
    }
    if (op.getResponse() != null &&
            op.getResponse().get("result") != null) {
        // 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"));

        for (String id: folderSet.keySet()) {
            folderList.add(
                    String.format("%s (%s)", folderSet.get(id), id));
        }
    }

    return folderList;
}

/**
 * Interpret an error response returned by the API and return a String
 * summary.
 *
 * @param op the Operation returning an error response
 * @return summary of error response, or null if Operation returned no
 *     error
 */
private 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"));

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

C#

// Create Google Apps Script API service.
string scriptId = "ENTER_YOUR_SCRIPT_ID_HERE";
var service = new ScriptService(new BaseClientService.Initializer()
    {
        HttpClientInitializer = credential,
        ApplicationName = ApplicationName,
    });

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

ScriptsResource.RunRequest runReq =
        service.Scripts.Run(request, scriptId);

try
{
    // Make the API request.
    Operation op = runReq.Execute();

    if (op.Error != null)
    {
        // The API executed, but the script returned an error.

        // Extract the first (and only) set of error details
        // as a IDictionary. The values of this dictionary are
        // the script's 'errorMessage' and 'errorType', and an
        // array of stack trace elements. Casting the array as
        // a JSON JArray allows the trace elements to be accessed
        // directly.
        IDictionary<string, object> error = op.Error.Details[0];
        Console.WriteLine(
                "Script error message: {0}", error["errorMessage"]);
        if (error["scriptStackTraceElements"] != null)
        {
            // There may not be a stacktrace if the script didn't
            // start executing.
            Console.WriteLine("Script error stacktrace:");
            Newtonsoft.Json.Linq.JArray st =
                (Newtonsoft.Json.Linq.JArray)error["scriptStackTraceElements"];
            foreach (var trace in st)
            {
                Console.WriteLine(
                        "\t{0}: {1}",
                        trace["function"],
                        trace["lineNumber"]);
            }
        }
    }
    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.
        // It is most convenient to cast the return value as a JSON
        // JObject (folderSet).
        Newtonsoft.Json.Linq.JObject folderSet =
                (Newtonsoft.Json.Linq.JObject)op.Response["result"];
        if (folderSet.Count == 0)
        {
            Console.WriteLine("No folders returned!");
        }
        else
        {
            Console.WriteLine("Folders under your root folder:");
            foreach (var folder in folderSet)
            {
                Console.WriteLine(
                    "\t{0} ({1})", folder.Value, folder.Key);
            }
        }
    }
}
catch (Google.GoogleApiException e)
{
    // The API encountered a problem before the script
    // started executing.
    Console.WriteLine("Error calling API:\n{0}", e);
}
Console.Read();

Go


scriptId := "ENTER_YOUR_SCRIPT_ID_HERE"
client := getClient(ctx, config)

// Generate a service object.
srv, err := script.New(client)
if err != nil {
  log.Fatalf("Unable to retrieve script Client %v", err)
}

// Create an execution request object.
req := script.ExecutionRequest{Function:"getFoldersUnderRoot"}

// Make the API request.
resp, err := srv.Scripts.Run(scriptId, &req).Do()
if err != nil {
  // The API encountered a problem before the script started executing.
  log.Fatalf("Unable to execute Apps Script function. %v", err)
}

if resp.Error != nil {
  // The API executed, but the script returned an error.

  // 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).
  error := resp.Error.Details[0].(map[string]interface{})
  fmt.Printf("Script error message: %s\n", error["errorMessage"]);

  if (error["scriptStackTraceElements"] != nil) {
    // There may not be a stacktrace if the script didn't start executing.
    fmt.Printf("Script error stacktrace:\n")
    for _, trace := range error["scriptStackTraceElements"].([]interface{}) {
      t := trace.(map[string]interface{})
      fmt.Printf("\t%s: %d\n", t["function"], int(t["lineNumber"].(float64)))
    }
  }
} 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 map (folderSet).
  r := resp.Response.(map[string]interface{})
  folderSet := r["result"].(map[string]interface{})
  if len(folderSet) == 0 {
    fmt.Printf("No folders returned!\n")
  } else {
    fmt.Printf("Folders under your root folder:\n")
    for id, folder := range folderSet {
      fmt.Printf("\t%s (%s)\n", folder, id)
    }
  }
}

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() {
  var 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)
  gapi.client.script.scripts.run({
    'scriptId': scriptId,
    'resource': {
      'function': 'getFoldersUnderRoot'
    }
  }).then(function(resp) {
    var 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.
      var 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 (var i = 0; i < error.scriptStackTraceElements.length; i++) {
          var 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).

      var 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  + ')');
        });
      }
    }
  });
}

Node.js

/**
 * Call an Apps Script function to list the folders in the user's root
 * Drive folder.
 *
 * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
 */
function callAppsScript(auth) { // eslint-disable-line no-unused-vars
  const scriptId = 'ENTER_YOUR_SCRIPT_ID_HERE';
  const script = google.script('v1');

  // Make the API request. The request object is included here as 'resource'.
  script.scripts.run({
    auth: auth,
    resource: {
      function: 'getFoldersUnderRoot',
    },
    scriptId: scriptId,
  }, function(err, resp) {
    if (err) {
      // The API encountered a problem before the script started executing.
      console.log('The API returned an error: ' + err);
      return;
    }
    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);
        });
      }
    }
  });
}

Objective-C

// Calls an Apps Script function to list the folders in the user's
// root Drive folder.
- (void)callAppsScript {
    // Create an execution request object.
    GTLRScript_ExecutionRequest *request = [GTLRScript_ExecutionRequest new];
    request.function = @"getFoldersUnderRoot";

    // Make the API request.
    GTLRScriptQuery_ScriptsRun *query =
    [GTLRScriptQuery_ScriptsRun queryWithObject:request
                                       scriptId:kScriptID];
    [self.service executeQuery:query
                      delegate:self
             didFinishSelector:@selector(displayResultWithTicket:finishedWithObject:error:)];
}

// Displays the retrieved folders returned by the Apps Script function.
- (void)displayResultWithTicket:(GTLRServiceTicket *)ticket
                     finishedWithObject:(GTLRScript_Operation *) response
                                  error:(NSError *)error {
    if (error == nil) {
        NSMutableString *output = [[NSMutableString alloc] init];
        if (response.error != nil) {
            // The API executed, but the script returned an error.

            // Extract the first (and only) set of error details and cast as a
            // NSDictionary. The values of this dictionary are the script's
            // 'errorMessage' and 'errorType', and an array of stack trace
            // elements (which also need to be cast as NSDictionaries).
            GTLRScript_Status_Details_Item *err = response.error.details[0];
            [output appendFormat:@"Script error message: %@\n",
             [err JSONValueForKey:@"errorMessage"]];

            if ([err JSONValueForKey:@"scriptStackTraceElements"]) {
                // There may not be a stacktrace if the script didn't start
                // executing.
                [output appendString:@"Script error stacktrace:\n"];
                for (NSDictionary *trace in [err JSONValueForKey:@"scriptStackTraceElements"]) {
                    [output appendFormat:@"\t%@: %@\n",
                     [trace objectForKey:@"function"],
                     [trace objectForKey:@"lineNumber"]];
                }
            }

        } 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 NSDictionary (folderSet).
            NSDictionary *folderSet = [response.response JSONValueForKey:@"result"];
            if (folderSet == nil) {
                [output appendString:@"No folders returned!\n"];
            } else {
                [output appendString:@"Folders under your root folder:\n"];
                for (id folderId in folderSet) {
                    [output appendFormat:@"\t%@ (%@)\n",
                     [folderSet objectForKey:folderId],
                     folderId];
                }
            }
        }
        self.output.text = output;
    } else {
        // The API encountered a problem before the script started executing.
        NSMutableString *message = [[NSMutableString alloc] init];
        [message appendFormat:@"The API returned an error: %@\n",
         error.localizedDescription];
        [self showAlert:@"Error" message:message];
    }
}

PHP

require __DIR__ . '/vendor/autoload.php';

// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Script($client);

$scriptId = 'ENTER_YOUR_SCRIPT_ID_HERE';

// Create an execution request object.
$request = new Google_Service_Script_ExecutionRequest();
$request->setFunction('getFoldersUnderRoot');

try {
  // Make the API request.
  $response = $service->scripts->run($scriptId, $request);

  if ($response->getError()) {
    // 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.
    $error = $response->getError()['details'][0];
    printf("Script error message: %s\n", $error['errorMessage']);

    if (array_key_exists('scriptStackTraceElements', $error)) {
      // There may not be a stacktrace if the script didn't start executing.
      print "Script error stacktrace:\n";
      foreach($error['scriptStackTraceElements'] as $trace) {
        printf("\t%s: %d\n", $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
    // PHP array (folderSet).
    $resp = $response->getResponse();
    $folderSet = $resp['result'];
    if (count($folderSet) == 0) {
      print "No folders returned!\n";
    } else {
      print "Folders under your root folder:\n";
      foreach($folderSet as $id => $folder) {
        printf("\t%s (%s)\n", $folder, $id);
      }
    }
  }
} catch (Exception $e) {
  // The API encountered a problem before the script started executing.
  echo 'Caught exception: ', $e->getMessage(), "\n";
}

Python

from __future__ import print_function
from googleapiclient import errors
from googleapiclient.discovery import build
from httplib2 import Http
from oauth2client import file as oauth_file, client, tools

def main():
    """Runs the sample.
    """
    SCRIPT_ID = 'ENTER_YOUR_SCRIPT_ID_HERE'

    # Setup the Apps Script API
    SCOPES = 'https://www.googleapis.com/auth/script.projects'
    store = oauth_file.Storage('token.json')
    creds = store.get()
    if not creds or creds.invalid:
        flow = client.flow_from_clientsecrets('credentials.json', SCOPES)
        creds = tools.run_flow(flow, store)
    service = build('script', 'v1', http=creds.authorize(Http()))

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

    try:
        # Make the API request.
        response = service.scripts().run(body=request,
                scriptId=SCRIPT_ID).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
            # an list of stack trace elements.
            error = response['error']['details'][0]
            print("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("\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 (folderSet).
            folderSet = response['response'].get('result', {})
            if not folderSet:
                print('No folders returned!')
            else:
                print('Folders under your root folder:')
                for (folderId, folder) in folderSet.iteritems():
                    print("\t{0} ({1})".format(folder, folderId))

    except errors.HttpError as e:
        # The API encountered a problem before the script started executing.
        print(e.content)


if __name__ == '__main__':
    main()

Ruby

SCRIPT_ID = 'ENTER_YOUR_SCRIPT_ID_HERE'.freeze

# Create an execution request object.
request = Google::Apis::ScriptV1::ExecutionRequest.new(
  function: 'getFoldersUnderRoot'
)

begin
  # Make the API request.
  resp = service.run_script(SCRIPT_ID, request)

  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.
    error = resp.error.details[0]

    puts "Script error message: #{error['errorMessage']}"

    if error['scriptStackTraceElements']
      # There may not be a stacktrace if the script didn't start executing.
      puts 'Script error stacktrace:'
      error['scriptStackTraceElements'].each do |trace|
        puts "\t#{trace['function']}: #{trace['lineNumber']}"
      end
    end
  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 Ruby hash (folderSet).
    folder_set = resp.response['result']
    if folder_set.empty?
      puts 'No folders returned!'
    else
      puts 'Folders under your root folder:'
      folder_set.each do |id, folder|
        puts "\t#{folder} (#{id})"
      end
    end
  end
rescue Google::Apis::ClientError
  # The API encountered a problem before the script started executing.
  puts 'Error calling API!'
end

Swift

// Calls an Apps Script function to list the folders in the user's
// root Drive folder.
func callAppsScript() {
    output.text = "Getting folders..."

    // Create an execution request object.
    let request = GTLRScript_ExecutionRequest()
    request.function = "getFoldersUnderRoot"

    // Make the API request.
    let query = GTLRScriptQuery_ScriptsRun.query(withObject: request, scriptId: kScriptId)
    service.executeQuery(query,
                         delegate: self,
                         didFinish: #selector(displayResultWithTicket(ticket:finishedWithObject:error:)))
}

// Displays the retrieved folders returned by the Apps Script function.
func displayResultWithTicket(ticket: GTLRServiceTicket,
                             finishedWithObject operation : GTLRScript_Operation,
                             error : NSError?) {
    if let error = error {
        // The API encountered a problem before the script
        // started executing.
        showAlert(title: "The API returned the error: ",
                  message: error.localizedDescription)
        return
    }

    if let apiError = operation.error {
        // The API executed, but the script returned an error.

        // Extract the first (and only) set of error details and cast as
        // a Dictionary. The values of this Dictionary are the script's
        // 'errorMessage' and 'errorType', and an array of stack trace
        // elements (which also need to be cast as Dictionaries).
        let err = apiError.details![0]
        var errMessage = String(
            format:"Script error message: %@\n",
            err.jsonValue(forKey: "errorMessage") as! String)

        if let stacktrace =
            err.jsonValue(forKey: "scriptStackTraceElements") as? [[String: AnyObject]] {
            // There may not be a stacktrace if the script didn't start
            // executing.
            for trace in stacktrace {
                let f = trace["function"] as? String ?? "Unknown"
                let num = trace["lineNumber"] as? Int ?? -1
                errMessage += "\t\(f): \(num)\n"
            }
        }

        // Set the output as the compiled error message.
        output.text = errMessage
    } 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 Dictionary
        // (folderSet).
        let folderSet = operation.response?.jsonValue(forKey: "result") as! [String: AnyObject]
        if folderSet.count == 0 {
            output.text = "No folders returned!\n"
        } else {
            var folderString = "Folders under your root folder:\n"
            for (id, folder) in folderSet {
                folderString += "\t\(folder) (\(id))\n"
            }
            output.text = folderString
        }
    }
}

Limitations

The Apps Script API has several limitations:

  1. A common Cloud Platform project. The script being called and the calling application must share a Cloud Platform project. This can be the default one created with the script, or another project (which requires switching the script to use that project). If using the default project of a script, be aware that when a script resides in a Team Drive your access to its Cloud Platform project may be restricted.

  2. Basic parameter and return types. The API cannot pass or return Apps Script-specific objects (such as Documents, Blobs, Calendars, Drive Files, etc.) to the application. Only basic types such as strings, arrays, objects, numbers, and booleans can be passed and returned.

  3. OAuth scopes. The API can only execute scripts that have at least one required scope. This means you cannot use the API to call a script that does not require authorization of one or more services.

  4. No triggers.The API cannot create Apps Script triggers.

Send feedback about...

Apps Script API
Apps Script API
Need help? Visit our support page.