L'API Google Apps Script fournit une méthode scripts.run
qui exécute à distance une fonction Apps Script spécifiée. Vous pouvez utiliser cette méthode dans une application appelante pour exécuter une fonction dans l'un de vos projets de script à distance et recevoir une réponse.
Conditions requises
Vous devez remplir les conditions préalables suivantes avant qu'une application appelante puisse utiliser la méthode scripts.run
. Vous devez:
Déployez le projet de script en tant qu'exécutable d'API. Vous pouvez déployer, désinstaller et redéployer des projets si nécessaire.
Fournissez un jeton OAuth correctement défini pour l'exécution. Ce jeton OAuth doit couvrir toutes les habilitations utilisées par le script, et pas seulement celles utilisées par la fonction appelée. Consultez la liste complète des champs d'application de l'autorisation dans la documentation de référence de la méthode.
Assurez-vous que le script et le client OAuth2 de l'application appelante partagent un projet Google Cloud commun. Le projet Cloud doit être un projet Cloud standard. Les projets par défaut créés pour les projets Apps Script ne suffisent pas. Vous pouvez utiliser un nouveau projet Cloud standard ou un projet existant.
Activez l'API Google Apps Script dans le projet Cloud.
Méthode scripts.run
La méthode scripts.run
nécessite des informations d'identification de clé pour s'exécuter:
- ID du projet de script.
- Nom de la fonction à exécuter.
- Liste des paramètres requis par la fonction (le cas échéant).
Vous pouvez éventuellement configurer votre script pour qu'il s'exécute en mode développement.
Ce mode s'exécute avec la version la plus récemment enregistrée du projet de script plutôt qu'avec la version la plus récemment déployée. Pour ce faire, définissez la valeur booléenne devMode
dans le corps de la requête sur true
. Seul le propriétaire du script peut l'exécuter en mode développement.
Gérer les types de données des paramètres
L'utilisation de la méthode scripts.run
de l'API Apps Script implique généralement d'envoyer des données à Apps Script en tant que paramètres de fonction et de récupérer des données en tant que valeurs renvoyées par la fonction. L'API ne peut accepter et renvoyer que des valeurs de types de base: chaînes, tableaux, objets, nombres et valeurs booléennes. Ils sont semblables aux types de base en JavaScript. Les objets Apps Script plus complexes, tels que Document ou Sheet, ne peuvent pas être transmis au projet de script ni à partir de celui-ci par l'API.
Lorsque votre application appelante est écrite dans un langage à typage fort tel que Java, elle transmet les paramètres sous la forme d'une liste ou d'un tableau d'objets génériques correspondant à ces types de base. Dans de nombreux cas, vous pouvez appliquer automatiquement des conversions de type simple. Par exemple, une fonction qui utilise un paramètre numérique peut recevoir un objet Java Double
, Integer
ou Long
comme paramètre sans traitement supplémentaire.
Lorsque l'API renvoie la réponse de la fonction, vous devez souvent caster la valeur renvoyée au type approprié avant qu'elle puisse être utilisée. Voici quelques exemples basés sur Java:
- Les nombres renvoyés par l'API à une application Java arrivent sous forme d'objets
java.math.BigDecimal
et peuvent nécessiter d'être convertis en typesDoubles
ouint
selon les besoins. Si la fonction Apps Script renvoie un tableau de chaînes, une application Java jette la réponse dans un objet
List<String>
:List<String> mylist = (List<String>)(op.getResponse().get("result"));
Si vous souhaitez renvoyer un tableau de
Bytes
, vous pouvez trouver utile d'encoder le tableau en tant que chaîne base64 dans la fonction Apps Script et de renvoyer cette chaîne à la place:return Utilities.base64Encode(myByteArray); // returns a String.
Les exemples de code ci-dessous illustrent comment interpréter la réponse de l'API.
Procédure générale
La procédure générale d'utilisation de l'API Apps Script pour exécuter des fonctions Apps Script est décrite ci-dessous:
Étape 1: Configurez le projet Cloud commun
Votre script et l'application appelante doivent partager le même projet Cloud. Ce projet Cloud peut être un projet existant ou un nouveau projet créé à cette fin. Une fois que vous avez un projet Cloud, vous devez passer à votre projet de script pour l'utiliser.
Étape 2: Déployez le script en tant qu'exécutable d'API
- Ouvrez le projet Apps Script contenant les fonctions que vous souhaitez utiliser.
- En haut à droite, cliquez sur Déployer > Nouveau déploiement.
- Dans la boîte de dialogue qui s'ouvre, cliquez sur "Activer les types de déploiement" > Exécutable de l'API.
- Dans le menu déroulant "Qui a accès", sélectionnez les utilisateurs autorisés à appeler les fonctions du script à l'aide de l'API Apps Script.
- Cliquez sur Déployer.
Étape 3: Configurer l'application appelante
L'application appelante doit activer l'API Apps Script et établir des identifiants OAuth avant de pouvoir l'utiliser. Pour ce faire, vous devez disposer d'un accès au projet Cloud.
- Configurez le projet Cloud utilisé par votre application appelante et votre script. Pour ce faire, procédez comme suit :
- Ouvrez le projet de script et, sur la gauche, cliquez sur Vue d'ensemble .
- Sous Champs d'application Oauth du projet, enregistrez tous les champs d'application requis par le script.
Dans le code de l'application appelante, générez un jeton d'accès OAuth de script pour l'appel d'API. Il ne s'agit pas d'un jeton utilisé par l'API elle-même, mais d'un jeton requis par le script lors de son exécution. Il doit être créé à l'aide de l'ID client du projet Cloud et des portées de script que vous avez enregistrées.
Les bibliothèques clientes Google peuvent grandement vous aider à créer ce jeton et à gérer OAuth pour l'application. Elles vous permettent généralement de créer un objet "identifiants" de niveau supérieur à l'aide des champs d'application du script. Pour obtenir des exemples de création d'un objet d'identifiants à partir d'une liste de champs d'application, consultez les guides de démarrage rapide de l'API Apps Script.
Étape 4: Effectuez la requête script.run
Une fois l'application appelante configurée, vous pouvez passer des appels scripts.run
. Chaque appel d'API se compose des étapes suivantes:
- Créez une requête API à l'aide de l'ID de script, du nom de la fonction et de tous les paramètres requis.
- Effectuez l'appel
scripts.run
et incluez le jeton OAuth du script que vous avez créé dans l'en-tête (si vous utilisez une requêtePOST
de base) ou utilisez un objet d'identifiants que vous avez créé avec les portées du script. - Attendez que l'exécution du script soit terminée. Les scripts peuvent prendre jusqu'à six minutes d'exécution. Votre application doit donc le permettre.
- À la fin, la fonction de script peut renvoyer une valeur, que l'API renvoie à l'application si la valeur est un type compatible.
Vous trouverez ci-dessous des exemples d'appels d'API script.run
.
Exemples de requêtes API
Les exemples suivants montrent comment envoyer une requête d'exécution d'API Apps Script dans différentes langues, en appelant une fonction Apps Script pour imprimer une liste de dossiers dans le répertoire racine de l'utilisateur. L'ID de script du projet Apps Script contenant la fonction exécutée doit être spécifié là où il est indiqué avec ENTER_YOUR_SCRIPT_ID_HERE
. Les exemples s'appuient sur les bibliothèques clientes des API Google pour leurs langues respectives.
Script cible
La fonction de ce script utilise l'API Drive.
Vous devez activer l'API Drive dans le projet hébergeant le script.
De plus, les applications appelantes doivent envoyer des identifiants OAuth qui incluent le champ d'application Drive suivant:
https://www.googleapis.com/auth/drive
Les exemples d'applications présentés ici utilisent les bibliothèques clientes Google pour créer des objets d'identifiants OAuth à l'aide de ce champ d'application.
/**
* 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()
Limites
L'API Apps Script présente plusieurs limites:
Un projet Cloud commun Le script appelé et l'application appelante doivent partager un projet Cloud. Le projet Cloud doit être un projet Cloud standard. Les projets par défaut créés pour les projets Apps Script ne suffisent pas. Le projet Cloud standard peut être un projet nouveau ou existant.
Types de paramètres et de renvois de base L'API ne peut pas transmettre ni renvoyer d'objets spécifiques à Apps Script (tels que des documents, des blobs, des agendas, des fichiers Drive, etc.) à l'application. Seuls les types de base tels que les chaînes, les tableaux, les objets, les nombres et les valeurs booléennes peuvent être transmis et renvoyés.
Champs d'application OAuth L'API ne peut exécuter que des scripts ayant au moins un champ d'application obligatoire. Cela signifie que vous ne pouvez pas utiliser l'API pour appeler un script qui ne nécessite pas l'autorisation d'un ou de plusieurs services.
Aucun déclencheur : l'API ne peut pas créer de déclencheurs Apps Script.