BlogProfile

GASをローカルで開発する

スムーズ社ではデータ分析の基板周辺は Google のプロダクトを中心に使っていて、Google App Script(GAS)が真価を発揮しそうな気がしたので環境構築してみた。

本職プログラマではないけど GAS は書くよ!みたいな人も多いのでは。

全てはエディタで書くために

GAS の Web UI はクソなのでエディタで書きたい。自分は普段 Visual Studio Code で書いてるのでここでかけたら最高。

まずは Google 製の CLI ツールである clasp をインストールする。

GitHub - google/clasp: 🔗 Command Line Apps Script Projects

🔗 Command Line Apps Script Projects. Contribute to google/clasp development by creating an account on GitHub.

github.com
GitHub
npm install @google/clasp -g

とりあえずこれで clasp コマンドが通るようになるはずなのでログインしてくよ。

clasp login

上記のコマンドを打つとブラウザが立ち上がってログインを求められるのでログインする。無事ログインに成功すると Saved the credentials to〜みたいなメッセージが表示されるのでこれで下準備は完了。

次に GAS プロジェクトを作成していく。プロジェクトを作成するディレクトリまで飛んで以下のコマンドを打つ。

clasp create

これで.clasp.json 等の必要なセットアップファイルが現れるので app.js 等好きな命名でスクリプトファイルをプロジェクトフォルダ内に作成し、clasp push コマンドで GAS のリモートワークスペース上に配置&実行することが出来る(clasp run コマンドでも可だが試していない)。

型が欲しい

型が欲しくなるのは当たり前(適当)。

GAS でスクリプト言語のプログラミング初めてやる人もせっかくなので型付きでやるべし(横暴)。

コンパイル前後のスクリプトファイルを分ける為以下のコマンドを打ってディレクトリを作成しておく。

mkdir src dist

node_modules が必要になるのでいつも通り npm init からのエンター連打で package.json を作成する。以下のコマンドで必要なパッケージを追加しておく。

yarn add @types/google-apps-script rimraf

ここで追加する@types/google-apps-script がメインで使用する GAS のグローバル宣言を内包した型定義ファイルになる。

また、型とコンパイルの設定をするため tsc --init コマンドを叩いて tsconfig.json も作成する。

tsc --init

以下のようなディレクトリ構成になるはず。これで最強(だと思う)の GAS 環境ができた。

.
├── src
│ └── ここにスクリプトファイルを作成して書く
├── dist
│ └── ここに/src ディレクトリのファイルがコンパイルされる
├── package.json
├── node_modules
│ └── modules
├── tsconfig.json
├── .clasp.json
└── appscript.json

試しに動かしてみる

試しにスプレッドシートに書き込んでみる。

まずは適当なスプレッドシートを作って URL の/spreadsheets/以降の文字列をメモっておく。これがスプレッドシート ID になる。

次にコード側。

GAS を使ってスプレッドシートに何か書き込みたい時は SpreadsheetApp を使用する。

これら GAS の interface はアンビエント宣言で読み込まれているので手動で読み込む必要はなし。

ここでは D の 6 列にあははは!って書き込んでみる。

function writeSpreadSheet(): void {
  const ss = SpreadsheetApp.openById('***さっきのスプレッドシートID ***')
  const targetSheet = ss.getSheetByName('***シート名***')

  if (targetSheet) {
    targetSheet.getRange('D6').setValue('あははは!')
  }
}

以下のコマンドを走らせてプッシュ。

rimraf ./dist && tsc && clasp push

次に GAS を開く。

clasp open

するとさっきのコード(コンパイル後)が置かれているので再生ボタンを押して実行!

無事書き込めてますね。

アンコール

もうちょい色々やれるアピールをするためにおなじみのスターウォーズ API を使ってスプレッドシートに書き込む処理を実装してみる。

function writeSpreadSheet(): void {
  const ss = SpreadsheetApp.openById('***さっきのスプレッドシートID ***')
  const targetSheet = ss.getSheetByName('***シート名***')

  interface SWAPIRes {
    name: string
    hair_color: string
    skin_color: string
    eye_color: string
    birth_year: string
    gender: string
  }

  const arr: SWAPIRes[] = []

  // API叩くくん
  const fetcher = (num: number) => {
    const res = UrlFetchApp.fetch(`https://swapi.dev/api/people/${num}/`)
    const data = JSON.parse(res.getContentText())
    return data
  }

  // 10番目まで取得してarrに追加
  for (let i = 1; i <= 10; i += 1) {
    arr.push(fetcher(i))
  }

  if (targetSheet) {
    const setter = (target: string, value: string) => {
      targetSheet.getRange(target).setValue(value)
    }

    // 1列目定義
    setter(`A1`, 'name')
    setter(`B1`, 'gender')
    setter(`C1`, 'eye_color')
    setter(`D1`, 'hair_color')

    // arrに合わせて実行
    arr.forEach((d, i) => {
      const targetIndex = i + 2
      setter(`A${targetIndex}`, d.name)
      setter(`B${targetIndex}`, d.gender)
      setter(`C${targetIndex}`, d.eye_color)
      setter(`D${targetIndex}`, d.hair_color)
    })
  }
}

これで実行すると

こんな感じでスターウォーズの登場人物達の情報 10 人分が載ったスプレッドシートが一瞬で完成!(いらね〜〜〜)

もちろん Big Query もいける ZE

ちょっと疲れたからコード例は若干割愛するけど以下のように BigQuery.Jobs で呼び出せる。

function bqRunner(): void {
  const projectId = '***BQのprojectId***'

  const runQuery = (): GoogleAppsScript.Bigquery.Schema.QueryResponse => {
    const query = `
      SELECT count(*) FROM \`***テーブル名***\`
      WHERE
        ***クエリ***
    `
    const request: GoogleAppsScript.Bigquery.Schema.QueryRequest = {
      query,
      useLegacySql: false
    }

    const result = BigQuery.Jobs?.query(request, projectId)

    if (!result) {
      throw new Error('no result')
    }
    return result
  }

  runQuery()
}

なぜか DefinitelyTyped の型定義ファイルにタイポが存在して BigQuery の定義がエラーになるので適当にルートに index.d.ts を作成して以下のアンビエント宣言を追加しておこう。

いつまでも直んなかったらプルリク立てるわ。

declare var BigQuery: GoogleAppsScript.Bigquery

BigQuery is not defined みたいなエラーが出る人は GAS のリソース > Google の拡張サービスから BIgQuery を有効にしておこう。

快適な GAS ライフを!

感想

この環境をもとに社内用に GAS のボイラープレート作っておいたらこの間一瞬役に立ったのでよかった。

Visual Studio みたいに使える Web エディターまあまあ存在するんだから Google は BQ にしろ GAS にしろもうちょっと使いやすいの実装して欲しいわね。