API скриптов Google Apps предоставляет метод scripts.run
, который удалённо выполняет указанную функцию скрипта Apps. Вы можете использовать этот метод в вызывающем приложении для удалённого запуска функции в одном из ваших проектов скриптов и получения ответа.
Требования
Прежде чем вызывающее приложение сможет использовать метод scripts.run
, необходимо выполнить следующие требования. Необходимо :
Разверните проект скрипта как исполняемый файл API. Вы можете развернуть, отменить и повторно развернуть проекты по мере необходимости.
Предоставьте OAuth-токен с корректной областью действия для выполнения. Этот OAuth-токен должен охватывать все области действия , используемые скриптом, а не только те, которые используются вызываемой функцией. Полный список областей действия авторизации см. в справочнике методов.
Убедитесь, что скрипт и клиент OAuth2 вызывающего приложения используют общий проект Google Cloud. Проект Cloud должен быть стандартным проектом Cloud ; проектов по умолчанию, созданных для проектов Apps Script, недостаточно. Вы можете использовать новый стандартный проект Cloud или существующий.
Включите API Google Apps Script в облачном проекте.
Метод scripts.run
Для запуска метода scripts.run
требуется ключевая идентификационная информация:
- Идентификатор проекта сценария .
- Имя функции, которую нужно выполнить.
- Список параметров, требуемых функцией (если таковые имеются).
При желании вы можете настроить скрипт для выполнения в режиме разработки . В этом режиме выполняется последняя сохранённая версия проекта скрипта, а не последняя развёрнутая версия. Для этого установите логическое значение devMode
в теле запроса в true
. Только владелец скрипта может выполнить его в режиме разработки.
Обработка типов данных параметров
Использование метода scripts.run
API Apps Script обычно подразумевает передачу данных в Apps Script в качестве параметров функции и получение данных обратно в виде возвращаемых ею значений. API может принимать и возвращать значения только базовых типов: строки, массивы, объекты, числа и логические значения. Они аналогичны базовым типам в JavaScript. Более сложные объекты Apps Script, такие как Document или Sheet, не могут быть переданы в проект скрипта или из него с помощью API.
Когда вызывающее приложение написано на языке со строгой типизацией, таком как Java, оно передаёт параметры в виде списка или массива универсальных объектов, соответствующих этим базовым типам. Во многих случаях можно автоматически применять простые преобразования типов. Например, функции, принимающей числовой параметр, можно передать в качестве параметра объект Java Double
, Integer
или Long
без дополнительной обработки.
Когда API возвращает ответ функции, часто требуется привести возвращаемое значение к правильному типу, прежде чем его можно будет использовать. Вот несколько примеров на Java:
- Числа, возвращаемые API в приложение Java, поступают как объекты
java.math.BigDecimal
и при необходимости могут потребовать преобразования в типыDoubles
илиint
. Если функция Apps Script возвращает массив строк, приложение Java преобразует ответ в объект
List<String>
:List<String> mylist = (List<String>)(op.getResponse().get("result"));
Если вы хотите вернуть массив
Bytes
, вам может быть удобно закодировать массив как строку base64 в функции Apps Script и вернуть эту строку:return Utilities.base64Encode(myByteArray); // returns a String.
Приведенные ниже примеры кода иллюстрируют способы интерпретации ответа API.
Общая процедура
Ниже описывается общая процедура использования API Apps Script для выполнения функций Apps Script:
Шаг 1: Настройте общий облачный проект
Ваш скрипт и вызывающее приложение должны использовать один и тот же проект Cloud. Этот проект Cloud может быть как существующим, так и новым, созданным специально для этой цели. После создания проекта Cloud необходимо переключить проект скрипта, чтобы использовать его .
Шаг 2: Разверните скрипт как исполняемый файл API
- Откройте проект Apps Script с функциями, которые вы хотите использовать.
- В правом верхнем углу нажмите Развернуть > Новое развертывание .
- В открывшемся диалоговом окне нажмите «Включить типы развертывания».
> Исполняемый API-файл .
- В раскрывающемся меню «У кого есть доступ» выберите пользователей, которым разрешено вызывать функции скрипта с помощью API Apps Script.
- Нажмите Развернуть .
Шаг 3: Настройте вызывающее приложение
Вызывающее приложение должно включить API Apps Script и настроить учётные данные OAuth, прежде чем его можно будет использовать. Для этого вам потребуется доступ к проекту Cloud.
- Настройте облачный проект, который используют ваше вызывающее приложение и скрипт. Это можно сделать, выполнив следующие шаги:
- Откройте проект скрипта и слева нажмите «Обзор» .
.
- В разделе Project Oauth scopes запишите все области, требуемые сценарием.
В коде вызывающего приложения сгенерируйте токен доступа OAuth скрипта для вызова API. Это не токен, который использует сам API, а тот, который требуется скрипту при выполнении. Он должен быть создан с использованием идентификатора клиента облачного проекта и записанных вами областей действия скрипта.
Клиентские библиотеки Google могут существенно помочь в создании этого токена и обработке OAuth для приложения, обычно позволяя вместо этого создать объект «учётных данных» более высокого уровня, используя области действия скрипта. Примеры создания объекта учётных данных из списка областей действия см. в кратких руководствах по API скриптов приложений .
Шаг 4: Выполните запрос script.run
После настройки вызывающего приложения можно выполнять вызовы scripts.run
. Каждый вызов API состоит из следующих этапов:
- Создайте запрос API, используя идентификатор скрипта, имя функции и любые необходимые параметры.
- Выполните вызов
scripts.run
и включите созданный вами токен OAuth скрипта в заголовок (если вы используете базовый запросPOST
) или используйте объект учетных данных, созданный вами с помощью областей действия скрипта. - Разрешите скрипту завершить выполнение. Скрипты могут выполняться до шести минут, поэтому ваше приложение должно это учитывать.
- По завершении функция скрипта может вернуть значение, которое API возвращает приложению, если значение поддерживается.
Примеры вызовов API script.run
вы можете найти ниже.
Примеры API-запросов
В следующих примерах показано, как выполнить запрос на выполнение API Apps Script на разных языках, вызывая функцию Apps Script для вывода списка папок в корневом каталоге пользователя. Идентификатор скрипта проекта Apps Script, содержащего выполняемую функцию, необходимо указать в месте, указанном с помощью ENTER_YOUR_SCRIPT_ID_HERE
. В примерах используются клиентские библиотеки Google API для соответствующих языков.
Целевой сценарий
Функция в этом скрипте использует API Диска.
Необходимо включить API Drive в проекте, где размещен скрипт.
Кроме того, вызывающие приложения должны отправлять учетные данные OAuth, которые включают следующую область действия Диска:
-
https://www.googleapis.com/auth/drive
В представленных здесь примерах приложений используются клиентские библиотеки Google для создания объектов учетных данных для OAuth с использованием этой области.
/**
* 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;
}
Ява
/**
* 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;
}
}
Питон
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()
Ограничения
API Apps Script имеет несколько ограничений:
Общий проект Cloud . Вызываемый скрипт и вызывающее приложение должны совместно использовать проект Cloud. Проект Cloud должен быть стандартным проектом Cloud ; проектов по умолчанию, созданных для проектов Apps Script, недостаточно. Стандартный проект Cloud может быть как новым, так и существующим.
Базовые параметры и возвращаемые типы данных . API не может передавать или возвращать приложению объекты, специфичные для Apps Script (например, Documents , Blob , Calendars , Drive Files и т. д.). Передаваться и возвращаться могут только базовые типы данных, такие как строки, массивы, объекты, числа и логические значения.
Области действия OAuth . API может выполнять только те скрипты, у которых есть хотя бы одна обязательная область действия. Это означает, что API нельзя использовать для вызова скрипта, не требующего авторизации одного или нескольких сервисов.
Нет триггеров . API не может создавать триггеры Apps Script.