Что такое Apps Script и зачем его развертывать в Google Sheets?
Google Apps Script — это облачная платформа для разработки скриптов на JavaScript, позволяющая расширять функциональность Google Workspace, включая Google Sheets. Развертывание скриптов позволяет автоматизировать рутинные задачи, создавать пользовательские функции, интегрировать внешние сервисы и строить сложные рабочие процессы непосредственно в таблицах.
В Google Sheets развертывание Apps Script открывает возможности для:
- Автоматизации: Обработка данных при их изменении, отправка уведомлений, генерация отчетов по расписанию.
- Кастомизации: Создание пользовательских меню, диалоговых окон, боковых панелей.
- Интеграции: Получение данных из внешних API (например, рекламных платформ, CRM), отправка данных во внешние системы.
- Валидации данных: Реализация сложных правил проверки данных, недоступных стандартными средствами.
Основные понятия: проекты Apps Script, триггеры, авторизация
- Проект Apps Script: Контейнер для вашего кода, настроек манифеста и связанных служб Google Cloud. Может быть привязан к конкретному документу Sheets (bound script) или существовать независимо (standalone script).
- Триггеры: Механизмы, запускающие выполнение скрипта в ответ на определенные события (открытие таблицы, редактирование ячейки, отправка формы, по времени) или при прямом вызове.
- Авторизация: Процесс предоставления скрипту разрешений на доступ к вашим данным Google Workspace или внешним сервисам. Скрипт запрашивает необходимые области (scopes) при первом запуске или развертывании, требуя вашего явного согласия.
Обзор различных способов развертывания Apps Script
Существует несколько основных способов развертывания Apps Script для использования в Google Sheets:
- Веб-приложение: Скрипт публикуется как веб-сервис с уникальным URL. Доступ к нему можно получить через
UrlFetchAppиз другого скрипта, использовать в качестве эндпоинта для внешних систем или встроить в интерфейс Sheets. - Дополнение Google Workspace (Add-on): Более сложный способ, позволяющий распространять скрипт через Google Workspace Marketplace. Требует строгого соблюдения гайдлайнов и процесса верификации.
- API Executable: Развертывание скрипта для вызова через Apps Script API. Полезно для интеграции с внешними приложениями.
- Библиотека: Публикация кода для повторного использования в других проектах Apps Script.
- Триггеры: Автоматический запуск функций скрипта по событиям или расписанию.
В этом руководстве мы сосредоточимся на развертывании в виде веб-приложений и с использованием триггеров, как наиболее распространенных и релевантных для Google Sheets сценариях.
Подготовка Apps Script к развертыванию
Написание и тестирование скрипта в редакторе Apps Script
Качественный код — основа успешного развертывания. Используйте встроенный редактор Apps Script (доступен из меню «Расширения» -> «Apps Script» в Google Sheets) или локальную среду разработки с clasp.
Рекомендации:
- Строгая типизация (JSDoc): Используйте аннотации JSDoc для описания типов переменных, параметров функций и возвращаемых значений. Это улучшает читаемость и помогает статическому анализу.
- Комментарии: Комментируйте сложные участки кода, описывайте назначение функций и их параметров.
- Форматирование: Придерживайтесь единого стиля форматирования (отступы, пробелы, именование переменных).
- Модульность: Разделяйте код на логические функции и модули.
- Тестирование: Тщательно тестируйте функции в редакторе, используя встроенные средства отладки и тестовые данные.
/**
* Получает данные о расходах из рекламной кампании по ее ID.
* @param {string} campaignId Идентификатор рекламной кампании.
* @param {string} apiKey Ключ API для доступа к внешнему сервису.
* @returns {number | null} Сумма расходов или null в случае ошибки.
* @customfunction
*/
function getCampaignSpend(campaignId: string, apiKey: string): number | null {
if (!campaignId || !apiKey) {
Logger.log('Ошибка: campaignId или apiKey не предоставлены.');
return null;
}
const apiUrl = `https://api.example-marketing.com/v1/campaigns/${campaignId}/spend`;
const options: GoogleAppsScript.URL_Fetch.URLFetchRequestOptions = {
'method': 'get',
'headers': {
'Authorization': `Bearer ${apiKey}`
},
'muteHttpExceptions': true // Не прерывать скрипт при ошибках HTTP
};
try {
const response = UrlFetchApp.fetch(apiUrl, options);
const responseCode = response.getResponseCode();
const responseBody = response.getContentText();
if (responseCode === 200) {
const data = JSON.parse(responseBody);
const spend: number = parseFloat(data.totalSpend);
Logger.log(`Расходы для кампании ${campaignId}: ${spend}`);
return !isNaN(spend) ? spend : null;
} else {
Logger.log(`Ошибка API (${responseCode}): ${responseBody}`);
return null;
}
} catch (error) {
Logger.log(`Исключение при вызове API: ${error}`);
return null;
}
}
Настройка манифеста проекта Apps Script (appsscript.json)
Манифест (appsscript.json) — это конфигурационный файл вашего проекта. Он определяет основные свойства скрипта, включая необходимые области авторизации (scopes), часовой пояс, зависимости и другие метаданные.
- Отображение: В редакторе выберите «Настройки проекта» (значок шестеренки) и включите опцию «Показывать файл манифеста appsscript.json».
oauthScopes: Критически важный раздел. Явно указывайте минимально необходимые области разрешений для вашего скрипта. Не запрашивайте лишних прав. Например, для чтения и записи в текущую таблицу достаточно"https://www.googleapis.com/auth/spreadsheets.currentonly", для вызова внешних сервисов —"https://www.googleapis.com/auth/script.external_request".runtimeVersion: Рекомендуется использовать последнюю стабильную версию среды выполнения (например,V8).timeZone: Установите часовой пояс, соответствующий вашим данным или ожидаемому поведению триггеров по времени.
{
"timeZone": "Europe/Moscow",
"dependencies": {
},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets.currentonly",
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/script.scriptapp", // Для управления триггерами
"https://www.googleapis.com/auth/script.container.ui" // Для пользовательского интерфейса
],
"webapp": {
"access": "MYSELF",
"executeAs": "USER_ACCESSING"
}
}
Обработка ошибок и логирование в Apps Script
Надежное развертывание требует продуманной обработки ошибок и логирования.
try...catch: Оборачивайте потенциально проблемные операции (вызовы API, работа с данными) в блокиtry...catchдля перехвата и обработки исключений.Logger/console.log: Используйте для записи отладочной информации и сообщений об ошибках во время разработки. Логи видны в редакторе Apps Script.- Логирование в Stackdriver/Google Cloud Logging: Для развернутых скриптов (особенно триггеров и веб-приложений) используйте интеграцию с Google Cloud Logging (
exceptionLogging: "STACKDRIVER"в манифесте). Это обеспечивает централизованное хранение и анализ логов выполнения и ошибок. - Пользовательское логирование в Таблицу: Для критически важных операций можно реализовать запись логов в отдельный лист Google Sheets для удобного мониторинга.
Развертывание Apps Script как веб-приложения
Веб-приложение позволяет вашему скрипту реагировать на HTTP-запросы (GET, POST). Это полезно для создания интерактивных элементов в Sheets или интеграции с внешними системами.
Создание нового развертывания веб-приложения
- В редакторе Apps Script нажмите кнопку «Развернуть» -> «Новое развертывание».
- Выберите тип развертывания: «Веб-приложение».
- Заполните описание развертывания (например, «v1.0 — API для отчетов по маркетингу»).
Настройка параметров развертывания: доступ, версии, права доступа
- «Выполнять как» (
Execute as):Я (you@example.com): Скрипт всегда выполняется от вашего имени, используя ваши разрешения. Подходит для доступа к ресурсам, которые есть только у вас.Пользователь, обращающийся к приложению (User accessing the web app): Скрипт выполняется от имени пользователя, который открыл URL. Пользователю потребуется авторизовать скрипт при первом доступе. Стандартный вариант для большинства интерактивных приложений.
- «Кто имеет доступ» (
Who has access):Только я: Доступ только для вас.Все пользователи в домене <your_domain.com>: Доступ для всех пользователей вашего Google Workspace домена (требуется авторизация).Все пользователи: Доступ для любого пользователя Google (требуется авторизация).Все пользователи (анонимно): Доступ для любого пользователя в интернете без входа в Google аккаунт. Используйте с крайней осторожностью, только если скрипт не работает с чувствительными данными и не требует авторизации.
Публикация веб-приложения и получение URL
После настройки нажмите «Развернуть». Apps Script предоставит вам два URL:
- URL приложения (
exec): Основной URL для выполнения вашего веб-приложения. - URL для разработки (
dev): URL, который всегда запускает последний сохраненный код, а не код конкретной версии развертывания. Используйте только для тестирования.
Важно: При внесении изменений в код, которые должны отразиться в развернутом веб-приложении, необходимо создавать новую версию развертывания («Развернуть» -> «Управление развертываниями» -> Выбрать развертывание -> «Изменить» (карандаш) -> «Версия: Новая версия»). Обновление dev-версии происходит автоматически при сохранении кода.
Примеры использования веб-приложения в Google Sheets (через формулы, кнопки)
Предположим, у нас есть веб-приложение с функцией doGet(e), которая возвращает данные в формате JSON.
/**
* Обрабатывает GET-запросы к веб-приложению.
* @param {GoogleAppsScript.Events.DoGet} e Объект события.
* @returns {GoogleAppsScript.Content.TextOutput} Ответ в формате JSON.
*/
function doGet(e: GoogleAppsScript.Events.DoGet): GoogleAppsScript.Content.TextOutput {
// Пример: возврат данных на основе параметра запроса
const campaignId = e.parameter.campaignId;
let data;
if (campaignId) {
// Здесь могла бы быть логика получения данных из внешнего API
// или другой таблицы, как в getCampaignSpend
data = { status: 'success', campaign: campaignId, clicks: Math.floor(Math.random() * 1000) };
} else {
data = { status: 'error', message: 'Параметр campaignId не указан' };
}
return ContentService.createTextOutput(JSON.stringify(data))
.setMimeType(ContentService.MimeType.JSON);
}
Использование в Google Sheets:
-
Через кнопку/рисунок:
- Нарисуйте фигуру в Sheets (Вставка -> Рисунок).
- Назначьте ей скрипт (правый клик -> Назначить скрипт).
- Введите имя функции, которая будет вызывать веб-приложение:
/** * Вызывает веб-приложение для получения данных и выводит их в лог. */ function callWebApp() { const webAppUrl = 'YOUR_WEB_APP_EXEC_URL'; // Замените на ваш URL const campaign = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange('A1').getValue(); // Берем ID из A1 try { const response = UrlFetchApp.fetch(`${webAppUrl}?campaignId=${encodeURIComponent(campaign)}`); const data = JSON.parse(response.getContentText()); if (data.status === 'success') { SpreadsheetApp.getUi().alert(`Кампания ${data.campaign}: ${data.clicks} кликов.`); } else { SpreadsheetApp.getUi().alert(`Ошибка: ${data.message}`); } } catch (error) { Logger.log(`Ошибка вызова веб-приложения: ${error}`); SpreadsheetApp.getUi().alert('Произошла ошибка при получении данных.'); } } -
Через пользовательскую функцию (менее предпочтительно для веб-приложений): Пользовательские функции имеют ограничения (не могут вызывать сервисы, требующие авторизации, как
UrlFetchApp). Для динамического обновления данных из веб-приложения лучше использовать кнопки, меню или триггеры.
Развертывание Apps Script с использованием триггеров
Триггеры запускают указанную функцию скрипта автоматически при наступлении определенных событий.
Типы триггеров:
- Простые триггеры (
Simple Triggers):- Имена функций зарезервированы:
onOpen(e),onEdit(e),onInstall(e),doGet(e),doPost(e). - Срабатывают автоматически при открытии/редактировании документа (если они определены).
- Имеют ограничения: не могут вызывать сервисы, требующие авторизации, ограничены по времени выполнения.
- Не требуют явного создания через интерфейс или код.
- Имена функций зарезервированы:
- Устанавливаемые триггеры (
Installable Triggers):- Создаются вручную или программно.
- Могут вызывать сервисы, требующие авторизации.
- Более гибкие типы событий: по времени (
time-driven), при отправке формы (on form submit), при изменении (on change— для структуры таблицы), календарные события. - Требуют явной авторизации при создании.
- Редактируемые триггеры: Это устанавливаемые триггеры, созданные для Дополнений Google Workspace.
Настройка триггеров вручную через интерфейс Apps Script
- В редакторе Apps Script перейдите в раздел «Триггеры» (значок будильника).
- Нажмите «+ Добавить триггер».
- Сконфигурируйте параметры:
- Функция для запуска: Выберите функцию из вашего скрипта.
- Развертывание для запуска: Обычно
Head(последний сохраненный код). - Источник события:
Из таблицыилиПо времени. - Тип события: Выберите конкретное событие (
При открытии,При редактировании,При изменении,При отправке формы,Минутный таймер,Часовой таймер,Дневной таймери т.д.). - Настройки уведомлений об ошибках: Укажите, как часто получать уведомления о сбоях триггера.
- Нажмите «Сохранить». Потребуется авторизация скрипта.
Создание триггеров программно с использованием Apps Script
Используйте сервис ScriptApp для динамического создания и управления триггерами.
/**
* Создает или обновляет дневной триггер для функции processDailyReports.
*/
function setupDailyTrigger(): void {
const functionName = 'processDailyReports';
// Удаляем существующие триггеры для этой функции, чтобы избежать дублирования
const triggers = ScriptApp.getProjectTriggers();
for (const trigger of triggers) {
if (trigger.getHandlerFunction() === functionName) {
ScriptApp.deleteTrigger(trigger);
Logger.log(`Удален старый триггер ID: ${trigger.getUniqueId()}`);
}
}
// Создаем новый триггер, срабатывающий каждый день в 3-4 утра
try {
const newTrigger = ScriptApp.newTrigger(functionName)
.timeBased()
.atHour(3) // Запускать в промежутке с 3:00 до 4:00
.everyDays(1) // Каждый день
.inTimezone(SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone()) // В часовом поясе таблицы
.create();
Logger.log(`Создан новый триггер ID: ${newTrigger.getUniqueId()} для функции ${functionName}`);
SpreadsheetApp.getUi().alert('Дневной триггер успешно настроен!');
} catch (error) {
Logger.log(`Ошибка создания триггера: ${error}`);
SpreadsheetApp.getUi().alert(`Не удалось создать триггер: ${error.message}`);
}
}
/**
* Пример функции, запускаемой триггером (заглушка).
*/
function processDailyReports(): void {
Logger.log('Запуск ежедневной обработки отчетов...');
// Здесь будет логика генерации или обработки отчетов
Utilities.sleep(5000); // Имитация работы
Logger.log('Ежедневная обработка отчетов завершена.');
}
Управление триггерами и их активация/деактивация
- Через интерфейс: В разделе «Триггеры» можно просмотреть, изменить, удалить или временно отключить (через редактирование и сохранение без изменений, если нет опции