عملکردها را با Apps Script API اجرا کنید

Google Apps Script API یک روش scripts.run را ارائه می دهد که از راه دور یک تابع Apps Script مشخص شده را اجرا می کند. می توانید از این روش در یک برنامه فراخوانی برای اجرای یک تابع در یکی از پروژه های اسکریپت خود از راه دور و دریافت پاسخ استفاده کنید.

الزامات

قبل از اینکه یک برنامه فراخوانی بتواند از روش scripts.run استفاده کند، باید شرایط زیر را برآورده کنید. شما باید :

  • پروژه اسکریپت را به عنوان یک API اجرایی اجرا کنید. می‌توانید پروژه‌ها را در صورت نیاز مستقر، undeploy و مجدداً مستقر کنید.

  • یک نشانه OAuth با محدوده مناسب برای اجرا ارائه دهید. این نشانه OAuth باید تمام حوزه های مورد استفاده اسکریپت را پوشش دهد، نه فقط مواردی که توسط تابع فراخوانی شده استفاده می شود. لیست کامل دامنه های مجوز را در مرجع روش مشاهده کنید.

  • اطمینان حاصل کنید که اسکریپت و سرویس گیرنده OAuth2 برنامه تماس گیرنده یک پروژه مشترک Google Cloud را به اشتراک می گذارند. پروژه Cloud باید یک پروژه استاندارد Cloud باشد. پروژه های پیش فرض ایجاد شده برای پروژه های Apps Script کافی نیستند. می توانید از یک پروژه استاندارد جدید Cloud یا یک پروژه موجود استفاده کنید.

  • Google Apps Script API را در پروژه Cloud فعال کنید .

روش scripts.run

متد scripts.run برای اجرا به اطلاعات شناسایی کلیدی نیاز دارد:

شما می توانید به صورت اختیاری اسکریپت خود را برای اجرا در حالت توسعه پیکربندی کنید. این حالت با آخرین نسخه ذخیره شده پروژه اسکریپت به جای جدیدترین نسخه اجرا شده اجرا می شود. این کار را با تنظیم boolean devMode در بدنه درخواست روی true انجام دهید. فقط صاحب اسکریپت می تواند آن را در حالت توسعه اجرا کند.

مدیریت انواع داده های پارامتر

استفاده از روش Apps Script API scripts.run معمولاً شامل ارسال داده به Apps Script به عنوان پارامترهای تابع و بازگرداندن داده ها به عنوان مقادیر بازگشتی تابع است. API فقط می تواند مقادیر را با انواع اصلی بگیرد و برگرداند: رشته ها، آرایه ها، اشیاء، اعداد و بولی. اینها شبیه به انواع پایه در جاوا اسکریپت هستند. اشیاء پیچیده‌تر Apps Script مانند Document یا Sheet نمی‌توانند توسط API به پروژه اسکریپت منتقل شوند یا از آن خارج شوند.

هنگامی که برنامه تماس شما به زبانی با نوع قوی مانند جاوا نوشته می شود، پارامترها را به عنوان لیست یا آرایه ای از اشیاء عمومی متناظر با این انواع اولیه ارسال می کند. در بسیاری از موارد، می توانید تبدیل نوع ساده را به صورت خودکار اعمال کنید. به عنوان مثال، تابعی که پارامتر عددی را می گیرد، می تواند یک شیء جاوا Double یا Integer یا Long به عنوان پارامتر بدون پردازش اضافی داده شود.

هنگامی که API پاسخ تابع را برمی‌گرداند، اغلب باید قبل از استفاده، مقدار بازگشتی را به نوع صحیح ارسال کنید. در اینجا چند نمونه مبتنی بر جاوا آورده شده است:

  • اعدادی که توسط API به یک برنامه جاوا بازگردانده می‌شوند به‌عنوان آبجکت‌های java.math.BigDecimal می‌آیند و ممکن است در صورت نیاز به Doubles یا int تبدیل شوند.
  • اگر تابع Apps Script آرایه‌ای از رشته‌ها را برمی‌گرداند، یک برنامه جاوا پاسخ را به یک شی 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: پروژه مشترک Cloud را راه اندازی کنید

هم اسکریپت شما و هم برنامه فراخوانی باید پروژه Cloud یکسانی را به اشتراک بگذارند. این پروژه Cloud می تواند یک پروژه موجود یا یک پروژه جدید باشد که برای این منظور ایجاد شده است. هنگامی که یک پروژه Cloud دارید، باید پروژه اسکریپت خود را برای استفاده از آن تغییر دهید .

مرحله 2: اسکریپت را به عنوان یک فایل اجرایی API اجرا کنید

  1. پروژه Apps Script را با توابعی که می خواهید استفاده کنید باز کنید.
  2. در بالا سمت چپ، روی Deploy > New Deployment کلیک کنید.
  3. در گفتگوی باز شده، روی Enable Deployment Types کلیک کنید > API اجرایی
  4. در منوی کشویی «چه کسی دسترسی دارد»، کاربرانی را انتخاب کنید که مجاز به فراخوانی عملکردهای اسکریپت با استفاده از Apps Script API هستند.
  5. روی Deploy کلیک کنید.

مرحله 3: برنامه تماس را پیکربندی کنید

برنامه تماس گیرنده باید قبل از استفاده، Apps Script API را فعال کند و اعتبار OAuth را ایجاد کند. برای انجام این کار باید به پروژه Cloud دسترسی داشته باشید.

  1. پروژه Cloud را که برنامه و اسکریپت تماس شما از آن استفاده می کند، پیکربندی کنید. با مراحل زیر می توانید این کار را انجام دهید:
    1. Apps Script API را در پروژه Cloud فعال کنید .
    2. صفحه رضایت OAuth را پیکربندی کنید .
    3. اعتبارنامه OAuth را ایجاد کنید .
  2. پروژه اسکریپت را باز کنید و در سمت چپ روی Overview کلیک کنید .
  3. در قسمت Project Oauth scopes ، تمام محدوده هایی را که اسکریپت نیاز دارد، ضبط کنید.
  4. در کد برنامه فراخوانی، یک نشانه دسترسی اسکریپت OAuth برای تماس API ایجاد کنید. این نشانه ای نیست که خود API از آن استفاده می کند، بلکه یکی از نشانه هایی است که اسکریپت هنگام اجرا به آن نیاز دارد. باید با استفاده از شناسه مشتری پروژه Cloud و محدوده‌های اسکریپتی که ضبط کرده‌اید ساخته شود.

    کتابخانه‌های سرویس گیرنده Google می‌توانند در ساختن این توکن و مدیریت OAuth برای برنامه بسیار کمک کنند، معمولاً به شما این امکان را می‌دهند که در عوض با استفاده از محدوده‌های اسکریپت یک شیء سطح بالاتر «معتبر» بسازید. برای نمونه‌هایی از ساختن یک شی اعتبارنامه از فهرستی از حوزه‌ها ، شروع سریع Apps Script API را ببینید.

مرحله 4: درخواست script.run را ارسال کنید

هنگامی که برنامه تماس پیکربندی شد، می توانید تماس های scripts.run برقرار کنید. هر فراخوانی API شامل مراحل زیر است:

  1. با استفاده از شناسه اسکریپت، نام تابع و هر پارامتر مورد نیاز، یک درخواست API بسازید.
  2. فراخوانی scripts.run را انجام دهید و توکن اسکریپت OAuth را که ساخته اید در هدر قرار دهید (اگر از یک درخواست اولیه POST استفاده می کنید) یا در غیر این صورت از یک شی اعتباری که با دامنه های اسکریپت ساخته اید استفاده کنید.
  3. اجازه دهید اسکریپت اجرا شود. اسکریپت ها مجاز هستند تا شش دقیقه زمان اجرا داشته باشند، بنابراین برنامه شما باید این اجازه را بدهد.
  4. پس از اتمام، تابع اسکریپت ممکن است مقداری را برگرداند که اگر مقدار از نوع پشتیبانی شده باشد، API آن را به برنامه بازگرداند.

می‌توانید نمونه‌هایی از فراخوان‌های API script.run را در زیر بیابید.

نمونه های درخواست API

مثال‌های زیر نشان می‌دهند که چگونه می‌توان یک درخواست اجرای Apps Script API را به زبان‌های مختلف ایجاد کرد، با فراخوانی یک تابع Apps Script برای چاپ فهرستی از پوشه‌ها در فهرست اصلی کاربر. شناسه اسکریپت پروژه Apps Script حاوی تابع اجرا شده باید در جایی که با ENTER_YOUR_SCRIPT_ID_HERE نشان داده شده است، مشخص شود. نمونه‌ها به کتابخانه‌های Google API Client برای زبان مربوطه خود متکی هستند.

اسکریپت هدف

تابع در این اسکریپت از Drive API استفاده می کند.

باید Drive API را در پروژه میزبان اسکریپت فعال کنید .

به‌علاوه، برنامه‌های فراخوانی باید اعتبارنامه‌های OAuth را ارسال کنند که شامل حوزه Drive زیر است:

  • 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);
  }
}

جاوا اسکریپت

/**
 * 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()

محدودیت ها

Apps Script API چندین محدودیت دارد:

  1. یک پروژه Cloud مشترک اسکریپت در حال فراخوانی و برنامه فراخوانی باید یک پروژه Cloud را به اشتراک بگذارند. پروژه Cloud باید یک پروژه استاندارد Cloud باشد. پروژه های پیش فرض ایجاد شده برای پروژه های Apps Script کافی نیستند. پروژه استاندارد Cloud می تواند یک پروژه جدید یا موجود باشد.

  2. پارامتر اصلی و انواع بازگشت API نمی‌تواند اشیاء خاص Apps Script (مانند اسناد ، حباب‌ها ، تقویم‌ها ، فایل‌های Drive ، و غیره) را به برنامه ارسال یا برگرداند. فقط انواع اولیه مانند رشته ها، آرایه ها، اشیاء، اعداد و بولی ها را می توان ارسال و برگرداند.

  3. دامنه های OAuth . API فقط می تواند اسکریپت هایی را اجرا کند که حداقل یک محدوده مورد نیاز دارند. این بدان معناست که شما نمی توانید از API برای فراخوانی اسکریپتی استفاده کنید که به مجوز یک یا چند سرویس نیاز ندارد.

  4. هیچ راه‌اندازی وجود ندارد . API نمی‌تواند محرک‌های Apps Script را ایجاد کند.