I have created a script in APPS script and deployed it as API Executable. I started to get 500 error when connecting to it. I decided to create a script from tutorial to localize the issue with this error. To my surprise i received the same results. Probably the issue is with service account, because i associated script with project where i have service account and i try to authorize with it.
I read that there were issues with connecting to Execution API with service account, which can still be true today.
***Update: I have successfully accessed Execution API with tutorial script when using OAuth2 user client ID. Is there still any issue with connecting to Execution API using Service Account?
Here is the Apps Script that i deployed as API Executable to the project where i have service account:
/**
* The function in this script will be called by the Apps Script Execution API. */
/**
* 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;
}
Here is my partly modified code that i took from tutorial. I changed it to work with service account:
from googlepackage.api_client import *
from googlepackage.constants import *
from googleapiclient.errors import HttpError
from httplib2 import Http
def __get_credentials(scopes: list) -> ServiceAccountCredentials:
credential_dir = os.path.join("..\\", SERVICE_ACCOUNT_FOLDER)
print(credential_dir)
if not os.path.exists(credential_dir):
raise Exception("Cannot find the directory with credentials")
try:
credentials = ServiceAccountCredentials.from_json_keyfile_name(
os.path.join(credential_dir, 'file.json'),
scopes)
except (ValueError, KeyError) as error:
raise Exception(error)
return credentials
def main():
"""Shows basic usage of the Apps Script Execution API.
Creates a Apps Script Execution API service object and uses it to call an
Apps Script function to print out a list of folders in the user's root
directory.
"""
SCRIPT_ID = 'API ID'
http_auth = __get_credentials([READ_AND_WRITE_SCOPE, DRIVE_API_SCOPE]).authorize(Http())
# Authorize and create a service object.
service = discovery.build('script', 'v1', http=http_auth)
# 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 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
# 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.items():
print("\t{0} ({1})".format(folder, folderId))
except HttpError as e:
# The API encountered a problem before the script started executing.
print(e.content)
if __name__ == '__main__':
main()
Here is the HttpError Content from my response:
b'{\n "error": {\n "code": 500,\n "message": "Internal error
encountered.",\n "errors": [\n {\n "message": "Internal error
encountered.",\n "domain": "global",\n "reason":
"backendError"\n }\n ],\n "status": "INTERNAL"\n }\n}\n'