generated at
Node.jsとasync-awaitでGoogle Spreadsheetに書く


Google Spreadsheetに毎日定期的に記録を書き込むやつを調べてやった
Node.jsを使った。



これを使うのが良かったshokaishokaishokaishokaishokai
google-spreadsheet npmをpromise化したやつなので、async-awaitで書ける
ワークシート名を指定して取得する関数にbugがあってpull request送った
mergeされたけどまだnpm publishされてないので、俺のgithubからインストールするといい
$ npm i shokai/node-google-spreadsheet-as-promised -save

実行する毎に一番下の行に現在の時刻を追記する例

add-date.js
import GoogleSpreadsheetAsPromised from 'google-spreadsheet-as-promised' const CREDS = require('./credentials.json') const SHEET_ID = '1Q9qh3rvFkkmrjeVvKCM4GtRNdd5QHNWkC2g4LlqmE4I'; // id from sheet URL // シート末尾を探す async function getTailRowIndex (worksheet) { const cells = (await worksheet.getCells('A1:A1500')).getAllValues() console.log(cells.length) for (let i = 0; i < cells.length; i++) { if (cells[i] === '') return i } } (async function () { const sheet = new GoogleSpreadsheetAsPromised() await sheet.load(SHEET_ID, CREDS) const worksheet = await sheet.getWorksheetByName('sheet1') // 事前にsheet1というシートを作っておく必要がある const tailRowIndex = await getTailRowIndex(worksheet) const cell = await worksheet.getCell(`A${tailRowIndex + 1}`) await cell.setValue(new Date().toString()) // 現在の日付を追記 console.log('done') })().catch(err => console.error(err.stack || err))
APIにはワークシートの末尾行を探す機能がたぶん無い
1列1500行取得して探すことにした
SHEET_ID はスプレッドシートのURL内にあるID
credentials.json は、Service Accountを作ると手に入る。
で詳しく解説されている
google developer consoleでprojectを作成し、 認証情報 から サービスアカウントキー を作成する

Service Accountとは
人間ではないbotアカウント
専用のメールアドレスが発行される
人間が普通にGoogle Spreadsheetを作成して、そこに共同編集者としてService Accountを招待して書き込ませる
特定の人間に紐付いていないので、作成者の退職等でアカウント削除してもService Accountは残る
認証情報は、アカウント作成時に1回だけダウンロードできる
JSON形式でもらえる
これを credentials.json にリネームして、上の add-date.js と同じディレクトリに置く
再ダウンロードはできない
この仕様は安全でとても良いと思う
認証情報無くしたら、再発行ではなくアカウントそのものを再作成する
client_email private_key を使って認証する
keyが漏れた時
特定のSpreadsheet専用のbotアカウントなので被害範囲をコントロールしやすい
対処しやすい
developer consoleからアカウントを削除する
sheetの共同編集者から削除する
普通のOAuthでtokenが漏れた場合は、applicationをrevokeしたり色々大変


Google公式のNode.jsライブラリが地雷だった
サンプルが無い
ドキュメントが無い
サンプルっぽいのがコード内に巨大なコメントアウトで埋め込まれているけど、肝心のrange等のプロパティが空でどうやって使うのかわからない
コード読んで理解しようと思ったけどgrepの邪魔でつらい

あとQuickstartの認証方法はService Accountではなく人間アカウントがOAuthでログインする方式なので、ただ記録を追記したいという目的には合わなかった。