Google Apps Script API มีเมธอด scripts.run
ที่เรียกใช้ฟังก์ชัน Apps Script ที่ระบุจากระยะไกล คุณสามารถใช้วิธีนี้ในแอปพลิเคชันการเรียกใช้เพื่อเรียกใช้ฟังก์ชันในโปรเจ็กต์สคริปต์จากระยะไกลและรับการตอบกลับ
ข้อกำหนด
คุณต้องปฏิบัติตามข้อกำหนดต่อไปนี้ก่อนที่แอปพลิเคชันการโทรจะใช้เมธอด scripts.run
ได้ คุณต้องดำเนินการดังนี้
ทำให้โปรเจ็กต์สคริปต์ใช้งานได้เป็นไฟล์ดำเนินการของ API คุณทำให้โปรเจ็กต์ใช้งานได้ ยกเลิกการทำให้ใช้งานได้ และทำให้โปรเจ็กต์ใช้งานได้อีกครั้งได้ตามต้องการ
ระบุโทเค็น OAuth ที่กำหนดขอบเขตอย่างเหมาะสมสำหรับการดำเนินการ โทเค็น OAuth นี้ต้องครอบคลุมขอบเขตทั้งหมดที่สคริปต์ใช้ ไม่ใช่แค่ขอบเขตที่ฟังก์ชันเรียกใช้ใช้ ดูรายการขอบเขตการให้สิทธิ์ทั้งหมดในข้อมูลอ้างอิงของวิธีการ
ตรวจสอบว่าสคริปต์และไคลเอ็นต์ OAuth2 ของแอปพลิเคชันที่เรียกใช้แชร์โปรเจ็กต์ Google Cloud ทั่วไป โปรเจ็กต์ที่อยู่ในระบบคลาวด์ต้องเป็นโปรเจ็กต์ Cloud มาตรฐาน เนื่องจากโปรเจ็กต์เริ่มต้นที่สร้างขึ้นสำหรับโปรเจ็กต์ Apps Script นั้นไม่เพียงพอ คุณจะใช้โปรเจ็กต์ Cloud มาตรฐานใหม่หรือโปรเจ็กต์ที่มีอยู่ก็ได้
เปิดใช้ Google Apps Script API ในโปรเจ็กต์ระบบคลาวด์
เมธอด scripts.run
เมธอด scripts.run
ต้องใช้ข้อมูลที่ระบุตัวตนคีย์เพื่อเรียกใช้งาน
- รหัสของโครงการสคริปต์
- ชื่อของฟังก์ชัน ที่จะดำเนินการ
- รายการพารามิเตอร์ที่ฟังก์ชันต้องใช้ (หากมี)
คุณเลือกกำหนดค่าสคริปต์ให้ทำงานในโหมดการพัฒนาได้
โหมดนี้จะดำเนินการกับโปรเจ็กต์สคริปต์เวอร์ชันที่บันทึกไว้ล่าสุด แทนที่จะเป็นเวอร์ชันที่ใช้งานล่าสุด ซึ่งทำได้ด้วยการตั้งค่าบูลีน devMode
ในเนื้อหาคำขอเป็น true
เฉพาะเจ้าของสคริปต์เท่านั้นที่สามารถเรียกใช้สคริปต์ในโหมดการพัฒนาได้
การจัดการประเภทข้อมูลพารามิเตอร์
การใช้เมธอด Apps Script API
scripts.run
มักจะเกี่ยวข้องกับการส่งข้อมูลไปยัง Apps Script เป็นพารามิเตอร์ฟังก์ชันและรับข้อมูลกลับมาเป็นค่าฟังก์ชันแสดงผล API จะใช้และแสดงผลค่าที่มีประเภทพื้นฐานเท่านั้น ได้แก่ สตริง อาร์เรย์ ออบเจ็กต์ ตัวเลข และบูลีน สิ่งเหล่านี้คล้ายกับประเภทพื้นฐานใน JavaScript ออบเจ็กต์ Apps Script ที่ซับซ้อนมากขึ้น เช่น Document หรือ Sheet จะไม่สามารถส่งผ่านไปยังหรือจากโปรเจ็กต์สคริปต์ผ่าน API ได้
เมื่อแอปพลิเคชันการโทรเขียนด้วยภาษาที่พิมพ์อย่างแรง เช่น Java แอปพลิเคชันจะส่งผ่านพารามิเตอร์เป็นรายการหรืออาร์เรย์ของออบเจ็กต์ทั่วไปที่สอดคล้องกับประเภทพื้นฐานเหล่านี้ ในหลายกรณี คุณสามารถใช้
Conversion ประเภทแบบง่ายโดยอัตโนมัติ เช่น ฟังก์ชันที่ใช้พารามิเตอร์ตัวเลขอาจกำหนดออบเจ็กต์ 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
ขั้นตอนทั่วไป
ขั้นตอนต่อไปนี้จะอธิบายถึงกระบวนการทั่วไปในการใช้ Apps Script API เพื่อเรียกใช้ฟังก์ชัน Apps Script
ขั้นตอนที่ 1: ตั้งค่าโปรเจ็กต์ที่อยู่ในระบบคลาวด์ทั่วไป
ทั้งสคริปต์และแอปพลิเคชันการโทรต้องแชร์โปรเจ็กต์ที่อยู่ในระบบคลาวด์เดียวกัน โปรเจ็กต์ที่อยู่ในระบบคลาวด์นี้อาจเป็นโปรเจ็กต์ที่มีอยู่หรือโปรเจ็กต์ใหม่ที่สร้างขึ้นเพื่อวัตถุประสงค์นี้ก็ได้ เมื่อมีโปรเจ็กต์ที่อยู่ในระบบคลาวด์แล้ว คุณต้องเปลี่ยนโปรเจ็กต์สคริปต์เพื่อใช้งาน
ขั้นตอนที่ 2: ทำให้สคริปต์ใช้งานได้เป็นไฟล์ดำเนินการของ API
- เปิดโปรเจ็กต์ Apps Script ที่มีฟังก์ชันที่ต้องการใช้
- คลิกทำให้ใช้งานได้ > การทำให้ใช้งานได้ใหม่ที่ด้านขวาบน
- ในกล่องโต้ตอบที่เปิดขึ้น ให้คลิกเปิดใช้ประเภทการทำให้ใช้งานได้ > ดำเนินการ API
- ในเมนูแบบเลื่อนลง "ผู้ที่มีสิทธิ์เข้าถึง" ให้เลือกผู้ใช้ที่ได้รับอนุญาตให้เรียกใช้ฟังก์ชันของสคริปต์โดยใช้ Apps Script API
- คลิกทำให้ใช้งานได้
ขั้นตอนที่ 3: กำหนดค่าแอปพลิเคชันการโทร
แอปพลิเคชันการเรียกใช้ต้องเปิดใช้ Apps Script API และสร้างข้อมูลเข้าสู่ระบบ OAuth ก่อนจึงจะใช้งานได้ คุณต้องมีสิทธิ์เข้าถึงโปรเจ็กต์ระบบคลาวด์จึงจะดำเนินการนี้ได้
- กำหนดค่าโปรเจ็กต์ที่อยู่ในระบบคลาวด์ที่แอปพลิเคชันการโทรและสคริปต์ของคุณใช้อยู่ โดยทำตามขั้นตอนต่อไปนี้
- เปิดโปรเจ็กต์สคริปต์และคลิกภาพรวม ทางด้านซ้าย
- ในส่วนขอบเขตของ Project OAuth ให้บันทึกขอบเขตทั้งหมดที่สคริปต์ต้องการ
ในโค้ดของแอปพลิเคชันที่เรียกใช้ ให้สร้างโทเค็นการเข้าถึง OAuth ของสคริปต์สำหรับการเรียก API ซึ่งไม่ใช่โทเค็นที่ API ใช้เอง แต่เป็นโทเค็นที่สคริปต์ต้องใช้เมื่อเรียกใช้ ซึ่งควรสร้างโดยใช้รหัสไคลเอ็นต์ของโปรเจ็กต์ที่อยู่ในระบบคลาวด์และขอบเขตสคริปต์ที่คุณบันทึกไว้
ไลบรารีไคลเอ็นต์ของ Google จะช่วยในการสร้างโทเค็นนี้และจัดการ OAuth สำหรับแอปพลิเคชันได้เป็นอย่างมาก ซึ่งปกติแล้วจะช่วยให้คุณสร้างออบเจ็กต์ "ข้อมูลเข้าสู่ระบบ" ระดับสูงขึ้นแทนโดยใช้ขอบเขตสคริปต์ได้ โปรดดูการเริ่มต้นใช้งาน Apps Script API อย่างรวดเร็วเพื่อดูตัวอย่างการสร้างออบเจ็กต์ข้อมูลเข้าสู่ระบบจากรายการขอบเขต
ขั้นตอนที่ 4: ส่งคำขอ script.run
เมื่อกำหนดค่าแอปพลิเคชันการโทรแล้ว คุณจะโทรออกผ่าน scripts.run
ได้ การเรียก API แต่ละรายการมีขั้นตอนต่อไปนี้
- สร้างคำขอ API โดยใช้รหัสสคริปต์ ชื่อฟังก์ชัน และพารามิเตอร์ที่จำเป็นทั้งหมด
- เรียกใช้
scripts.run
แล้วรวมโทเค็น OAuth ของสคริปต์ที่สร้างไว้ในส่วนหัว (หากใช้คำขอPOST
พื้นฐาน) หรือใช้ออบเจ็กต์ข้อมูลเข้าสู่ระบบที่คุณสร้างขึ้นด้วยขอบเขตสคริปต์ - ปล่อยให้สคริปต์ทำงานให้เสร็จสิ้น สคริปต์ต่างๆ อาจใช้เวลาดำเนินการถึง 6 นาที ดังนั้นแอปพลิเคชันของคุณจึงควรจะอนุญาต
- เมื่อดำเนินการเสร็จสิ้นแล้ว ฟังก์ชันสคริปต์อาจแสดงผลค่า ซึ่ง API จะส่งกลับไปยังแอปพลิเคชันหากค่าเป็นประเภทที่รองรับ
ดูตัวอย่างการเรียก API script.run
ได้ที่ด้านล่าง
ตัวอย่างคําขอ API
ตัวอย่างต่อไปนี้แสดงวิธีส่งคำขอเรียกใช้ Apps Script API ในภาษาต่างๆ โดยการเรียกใช้ฟังก์ชัน Apps Script เพื่อพิมพ์รายการโฟลเดอร์ในไดเรกทอรีรูทของผู้ใช้ ต้องระบุรหัสสคริปต์ของโปรเจ็กต์ Apps Script ที่มีฟังก์ชันดำเนินการเมื่อระบุด้วย ENTER_YOUR_SCRIPT_ID_HERE
ตัวอย่างนี้ใช้ไลบรารีของไคลเอ็นต์ Google API สำหรับภาษานั้นๆ
สคริปต์เป้าหมาย
ฟังก์ชันในสคริปต์นี้ใช้ API ไดรฟ์
คุณต้องเปิดใช้ API ไดรฟ์ในโปรเจ็กต์ที่โฮสต์สคริปต์
นอกจากนี้ แอปพลิเคชันการโทรต้องส่งข้อมูลเข้าสู่ระบบ 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;
}
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()
ข้อจำกัด
Apps Script API มีข้อจำกัดหลายประการดังนี้
โปรเจ็กต์ที่อยู่ในระบบคลาวด์ทั่วไป สคริปต์ที่กำลังเรียกใช้และแอปพลิเคชันการเรียกใช้ต้องแชร์โปรเจ็กต์ที่อยู่ในระบบคลาวด์ โปรเจ็กต์ที่อยู่ในระบบคลาวด์ต้องเป็นโปรเจ็กต์ Cloud มาตรฐาน เนื่องจากโปรเจ็กต์เริ่มต้นที่สร้างขึ้นสำหรับโปรเจ็กต์ Apps Script นั้นไม่เพียงพอ โปรเจ็กต์ Cloud มาตรฐานอาจเป็นโปรเจ็กต์ใหม่หรือโปรเจ็กต์ที่มีอยู่ก็ได้
พารามิเตอร์พื้นฐานและประเภทการแสดงผล API จะไม่สามารถส่งหรือส่งกลับออบเจ็กต์เฉพาะ Apps Script (เช่น เอกสาร, Blobs, ปฏิทิน, ไฟล์ในไดรฟ์ ฯลฯ) ไปยังแอปพลิเคชันได้ เฉพาะประเภทพื้นฐาน เช่น สตริง อาร์เรย์ ออบเจ็กต์ ตัวเลข และบูลีน เท่านั้นที่ส่งและแสดงผลได้
ขอบเขต OAuth API จะดำเนินการกับสคริปต์ที่มีขอบเขตที่จำเป็นอย่างน้อย 1 ขอบเขตเท่านั้น ซึ่งหมายความว่าคุณจะใช้ API เพื่อเรียกใช้สคริปต์ที่ไม่จำเป็นต้องมีการให้สิทธิ์จากบริการอย่างน้อย 1 บริการได้
ไม่มีทริกเกอร์ API จะสร้างทริกเกอร์ Apps Script ไม่ได้