エンジニアのための Google Apps Script 入門

社内に GAS の普及活動をした際の資料を公開したものです。

# はじめに

Google Apps Script（以降、GAS ／ガス） のいろはをまとめました。
GAS の入門記事というと、ノンプログラマー向けに書かれた記事の方が目立ち、
エンジニアが気になる点について入門記事では言及されていないことが多いということで、
エンジニア向けの入門記事として書いてます。

# Google Apps Script とは

Google が 2009 年頃から提供されているローコードプラットフォームです。

ローコードと言ってますが、 GUI で何か作れるわけではありません。
基本はすべてコーディングしていくことになりますが、
JavaScript がもとになっているため汎用性が高く、
開発環境はブラウザだけでいいのでプログラミング初心者でも始めやすい言語として認知されています。
また、共通ライブラリが作成できたり、
ローカル環境に限られますが TypeScript による開発もサポートされていたりするため、
軽いプログラムからそこそこ規模の大きいプロジェクトまで開発することが可能です。

# 主な特徴

<dl>
  <dt>無料</dt>
  <dd>AWS などとは違い、使い過ぎても実行ができなくなるだけで追加料金は発生しません。</dd>
  <dt>PC 起動は不要</dt>
  <dd>Google のクラウド上で実施できるため、起動設定などをしておけば PC を立ち上げなくてもプログラムが実行できます。</dd>
  <dt>環境構築が不要</dt>
  <dd>ブラウザ上でコーディング作業や作成したプログラムの実行ができます。<br>
例えば、ブラウザのアドレスバーに <a href="https://script.new/">script.new</a> でアクセスすれば
以下のようなオンライン IDE がすぐ利用できます。</dd>
</dl>

![online_ide.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114728/ad33bdae-66a2-e201-b4bc-9a63b0c63434.png)

# 汎用性の高さ

JavaScript で開発できる GAS ですが、実装における自由度はローコードと言うと誤解を招いてしまうほど広いです。

以下、その特徴を３つに整理しました。

<dl>
  <dt>JavaScript のライブラリが使える</dt>
  <dd>例えば、Lodash や Day.js, Cheerio などが利用できます。（利用方法に関しては後述）</dd>
  <dt>UrlFetchService により HTTP 通信が可能</dt>
  <dd>LINE や Twitter などの Bot 作成や任意のウェブサイトのスクレイピングなどもできます。<br>
GAS は Google 関連サービス（Gmail や Sheets など）との親和性が高いのが売りですが、
この UrlFetchService によりそれ以外のサービスとも連携可能です。</dd>
  <dt>起動オプションが豊富（スケジュール、イベント、手動）</dt>
  <dd>特にスケジュール機能は最頻度1分ごとに起動ができるため、<br>リアルタイムで Web の更新情報を取りたい場合に便利です。</dd>
</dl>

# 事例紹介

既に記載している通り、汎用性が高いため様々なプログラムが作成できますが、
例としていくつか列挙しておきます。

<dl>
  <dt>各 Google サービスとの連携</dt>
  <dd>Google Drive 上のファイルが更新されたことを Gmail で通知する<br>
Google Calendar の予定を自動で登録・編集する<br>
Google Spreadsheet でカスタム関数を作る</dd>
  <dt>その他のサービスとの連携</dt>
  <dd>Google Form で入力されたデータを Slack に転送する<br>
天気予報をスクレイピングで取得し、LINE に通知する</dd>
  <dt>サービスとの連携以外</dt>
  <dd>HtmlService を使って動的な Web ページを作成する</dd>
</dl>

![GAS でできること.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114728/f849da21-2adf-ac9a-7301-f704c1343e03.png)

# できないこと

これまでの説明ですと何でもできると思いがちになるので、
逆にできないところも載せておきます。

<dl>
  <dt>負荷の高い処理</dt>
  <dd>1回あたり 6 分、1日あたり 90 分までしか実行ができません。</dd>
  <dt>JavaScript 以外の言語での実装</dt>
  <dd>ローカル環境を整えれば TypeScript などの AltJS でも実装は可能です。</dd>
 <dt>ローカルでの実行は不可</dt>
  <dd>ローカル環境を整えたとしても、GAS の組み込みライブラリ（例えば SpreadsheetService など）はローカルでそのまま実施することができません。<br>
ただ、 Jest などの Mock ライブラリを使ってそれ以外の部分を実行することはできます。</dd>
</dl>

ちなみに、1回あたり6分などの上限については以下のページで確認できます。
[Quotas for Google Services ](https://developers.google.com/apps-script/guides/services/quotas)

# JavaScript との違い

GAS は JavaScript でのコーディングが可能ですが、
JavaScript といっても Web ブラウザや Node.js の環境で実行するときとちょっと違いがあります。

## １．名前空間

通常の JavaScript では、別ファイルで定義された関数やクラスを利用したい場合、
import や require で別ファイルのモジュール名を指定して読み込む必要がありますが、
GAS ではそれらの文は必要ありません。

GAS で複数ファイルを作成することはできますが、それらは実行時にアルファベット順に連結された１つのファイルに書かれたコードと見做されて実行されます。

そのため、名前空間というのは存在していません。
この辺は一昔前の JavaScript のような対策で名前空間を持たせるような書き方は可能ではあります。

ただ、ローカル環境でコーディングする場合は、webpack などが使えるため、
名前空間に対して何らかの特別な実装が必要というわけではなりません。

ただ、その場合、gas-webpack-plugin を使うと便利です。
https://github.com/fossamagna/gas-webpack-plugin

## ２．組み込み API

Web ブラウザで実行される JavaScript の場合、window オブジェクトや document オブジェクトが利用できますが、 GAS の場合はこれらの Web ブラウザ固有の組み込み API は存在してません。
GAS では GmailApp や SpreadsheetApp など、Google サービス関連の API や UriFetchApp や HtmlService などのユーティリティ関連の API がサポートされています。

以下、実行環境ごとに整理してみました。

![GAS 組み込みオブジェクト.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114728/815050f2-2d2e-24ee-7f76-41793623e8e0.png)

上記の図で分かる通り、EcmaScript で定義されているオブジェクトは利用できますが、
それぞれの実行環境に依存する API は利用できません。

GAS 上でも EcmaScript の文法や組み込みオブジェクトが問題なく実行できるかどうかは以下の記事が詳しいです。
[Google Apps ScriptのV8 Runtime対応を検証してみた](https://officeforest.org/wp/2020/02/06/google-apps-script%E3%81%AEv8-runtime%E5%AF%BE%E5%BF%9C%E3%82%92%E6%A4%9C%E8%A8%BC%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F/)

## ３．ブロッキング処理

Web ブラウザや Node.js などの環境で JavaScript を実行する場合、
ノンブロッキングで基本的には処理されます。

例えば、Web ブラウザで 1000 ミリ秒停止する処理を書いた場合、
以下のようにブラウザの機能（setTimeout は Web ブラウザに依存している組み込み関数）に依存している文は非同期で実行されます。

```javascript
setTimeout(() => console.log('Hello'), 1000)
console.log('World')
//=>World
//=>Hello
```

これは Node.js でも同様です。
ただ一方、 GAS では、ノンブロッキングではなく、
ブロッキング処理が採用されているため、Java や Python と同じ感覚で書けます。

```javascript
function sleep(callback, ms) {
  Utilities.sleep(ms)
  return callback()
}


function demo() {
  sleep(() => console.log('Hello'), 1000)
  console.log('World')
  //=>Hello
  //=>World
}
```

# 補足

以下、紹介しきれなかった GAS の Tips です。

## JavaScript ライブラリを GAS で使う方法

GAS ではエディタ上にある「ライブラリ」からスクリプトIDを指定すると、
他の GAS プロジェクトのコードを読み込むことができます。

普通の JavaScript ライブラリも GAS で使いたい機会は多いのですが、
この「ライブラリ」機能を使うことで任意のライブラリが利用可能になります。

※ もちろん、Web ブラウザや Node.js などのランタイムに依存しているライブラリは利用不可です。

以下は、試しに Day.js を一旦 GAS プロジェクトで定義しているコードです。

```javascript
eval(UrlFetchApp.fetch('https://cdn.jsdelivr.net/npm/dayjs@1.11.3/dayjs.min.js').getContentText());
```

スクリプトIDはエディタの URL から取得できます。

```
https://script.google.com/home/projects/(この部分です)/edit
```

上記のライブラリを別の GAS で読み込む際にスクリプトIDとバージョン、ライブラリ名を指定することで、利用可能になります。

バージョンは HEAD にすれば、常に最新のコードを読み込んでくれます。
ライブラリ名は任意でいいので、今回は dayjs と付けました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114728/c1a7273e-cc11-ed13-e146-4c9d1f549c0e.png)

上記の設定をすれば、以下のようなコードで day.js が利用できます。

```javascript
function myFunction() {
  const now = dayjs.dayjs();
  console.log(now.format());
}
```

## スタンドアロン型とコンテナバインド型

GAS プロジェクトを作成するにあたり、
まず、スタンドアロン型にするのか、コンテナバインド型にするかを選ぶ必要があります。

スタンドアロン型とは、Spreadsheet、Document、Slide、Form、または Site にバインドされていないスクリプトのことです。
Google Drive 上でファイルとして表示されます。
一方コンテナバインド型のスクリプトは、Spreadsheet や Document の中に組み込まれるため、
Google Drive 状では単一ファイルとしては表示されず、Spreadsheet や Document 経由でアクセスすることになります。

それぞれのメリットデメリットはこちらです。
どちらが優れているというわけではなく、用途によって使い分けしていくようになります。

### スタンドアロン型のメリット

1. Google Drive 上で表示されるため管理がしやすい。
1. Spreadsheet とは紐づかないため、利用者に対しスクリプトの内容を非公開にできる。

### コンテナバインド型のメリット

1. 各 Google のサービス内のメニューから手軽に始められる。
1. 紐づく Google のサービスには ID 指定が不要となる。

## ローカルでの開発

定番なのは、 TypeScript + clasp + VS Code の構成です。
ステップ数が多くなるとローカルでの開発はほぼ必須になる気がします。
GAS エディタはファイル自体は複数作成できるものの名前空間が一つしか持てません。
また、コードの静的解析、自動テスト、参照個所の検索、
バージョン管理などもローカルではないと行えないため、
その辺を使いたいという状況になったら、 clasp でローカル環境を整えると幸せになります。

実際にローカル上でプロジェクトを作成する際は、
以下のような Template リポジトリを使うことをお勧めします。

[Google App Script 開発 のための Templateリポジトリを作った](https://zenn.dev/ryo_kawamata/articles/2c6cc4e7c27210)

または、2023年3月からは Google から aside という
clasp プロジェクトのひな型作成ツールもリリースされているので、
こちらを使ってもいいかもしれません。

[google/aside - GitHub](https://github.com/google/aside)

# 各種ドキュメント

GAS の公式ドキュメントについてはこちら。英語のみです。
[Google Apps Script overview](https://developers.google.com/apps-script/overview)

clasp の使い方についてはこちら。
[GAS のGoogle製CLIツール clasp](https://qiita.com/HeRo/items/4e65dcc82783b2766c03)

ライブラリ、テンプレート、コードスニペットなどはこちら。
[contributorpw/google-apps-script-awesome-list - GitHub](https://github.com/contributorpw/google-apps-script-awesome-list)

[Google Apps Script にタグ付けされた Qiita の記事](https://qiita.com/search?q=tag%3Agoogleappsscript&sort=like)
[Google Apps Script Topic の Zenn の記事](https://zenn.dev/topics/googleappsscript)