I created a very simple app script that returns ContentService.createTextOutput("Hello")
, associated it with a Google Cloud project, and created a JavaScript program to get the return value. I can successfully execute, deploy, and use the link from the deploy screen and everything works as expected. The JavaScript program returns
"The script completed but the returned value is not a supported return type."
When I look at the log, I can see the script did complete. The Cloud Project has Drive API enabled (even though I don't use it) and I specified that scope as well when creating the token.
Here is the JavaScript code:
example.ts
import * as google from "googleapis";
import { authorizePromise } from "./authorizePromise";
import * as dotenv from "dotenv";
dotenv.config();
main();
async function main() {
const auth = await authorizePromise();
console.log("abut to call");
callAppsScript(auth);
}
/**
* 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) {
var scriptId = process.env.SCRIPT_ID;
console.log("Script ID: ", scriptId);
var script = new google.script_v1.Script({});
// Make the API request. The request object is included here as 'resource'.
console.log("running", auth);
script.scripts.run(
{
auth: auth,
scriptId: scriptId,
requestBody: { function: "doGet", devMode: true },
},
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.
var 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 (var i = 0; i < error.scriptStackTraceElements.length; i ) {
var 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).
console.log(
"debug",
resp,
"response",
Object.keys(resp),
Object.values(resp),
// "resp data",
// Object.keys(resp.data),
// "xxxxx",
// Object.values(resp.data),
// "xxxxx",
// Object.keys(resp.data.response),
// "xxxxx",
// Object.values(resp.data.response),
JSON.stringify(resp)
);
var folderSet = resp.data.response;
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);
});
}
}
}
);
}
authorizePromise.ts
const fs = require("fs");
const readline = require("readline");
const { google } = require("googleapis");
// If modifying these scopes, delete token.json.
const SCOPES = ["https://www.googleapis.com/auth/drive"];
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
const TOKEN_PATH = "token.json";
/**
* Create an OAuth2 client with the given credentials, and then execute the
* given callback function.
* @param {Object} credentials The authorization client credentials.
* @param {function} callback The callback to call with the authorized client.
*/
export async function authorizePromise() {
const credentials = JSON.parse(
fs.readFileSync("credentials.json").toString()
);
return new Promise((resolve) => {
resolve(authorize(credentials, resolve));
});
}
async function authorize(credentials, callback) {
console.log("authorize", credentials);
const { client_secret, client_id, redirect_uris } = credentials.installed;
console.log("authorize 3", client_secret, client_id, redirect_uris);
const oAuth2Client = new google.auth.OAuth2(
client_id,
client_secret,
redirect_uris[0]
);
// Check if we have previously stored a token.
let token;
try {
token = JSON.parse(fs.readFileSync(TOKEN_PATH).toString());
} catch {
token = await getAccessTokenPromise(oAuth2Client);
}
console.log("token", token);
oAuth2Client.setCredentials(token);
console.log("authorize 4");
callback(oAuth2Client);
}
function getAccessTokenPromise(oAuth2Client) {
return new Promise((resolve) => {
getAccessToken(oAuth2Client, resolve);
});
}
/**
* Get and store new token after prompting for user authorization, and then
* execute the given callback with the authorized OAuth2 client.
* @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.
* @param {getEventsCallback} callback The callback for the authorized client.
*/
function getAccessToken(oAuth2Client, callback) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: "offline",
scope: SCOPES,
});
console.log("Authorize this app by visiting this url:", authUrl);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question("Enter the code from that page here: ", (code) => {
rl.close();
oAuth2Client.getToken(code, (err, token) => {
if (err) return console.error("Error retrieving access token", err);
console.log("token", token);
oAuth2Client.setCredentials(token);
console.log("Going here");
console.log("g", JSON.stringify(token));
// Store the token to disk for later program executions
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
console.log("Err?", token, err);
if (err) return console.error(err);
console.log("Token stored to", TOKEN_PATH);
});
callback(oAuth2Client);
});
});
}
CodePudding user response:
ContentService
creates a TextOutput
object, which is not supported as a return type by the api. Use primitive return types like string
or number
:
return "Hello";
CodePudding user response:
That was it - return "hello", so simple!