Lambdaカクテル

京都在住Webエンジニアの日記です

Invite link for Scalaわいわいランド

ScalaからGoogleSpreadsheetに書き込んだ

ScalaでGoogle Spreadsheetに書き込んでみたメモです。

概要

先日Asanaからデータを取り出してCSVを生成するツールを書いた。

blog.3qe.us

CSVにできたのでこれを今度はGoogle Spreadsheetに自動転記したいと思い、試行錯誤していたところ、Java SDKを使って任意のシートの任意のRangeを書き換えられたのでメモ。

とその前に、設定ファイルまわりちゃんとしておく

外部アプリケーションとの連携ではトークンやら設定やらが沢山登場する。でも、ハードコードはしたくないので、HOCONで設定できるようにした。

github.com

めちゃくちゃ簡単に使えるので、とにかくこれでいいやという感じ。

例によってsbtに依存性を書き込む。

libraryDependencies += "com.typesafe" % "config" % "1.4.1"

アプリケーションから呼び出すためのインターフェイスを用意しておく。

package exporter

import com.typesafe.config.ConfigFactory

object Config {
  lazy val config = ConfigFactory.load()
}

あとはimport Config.configしておけばいつでもconfig.getString("hoge")みたいなことができる。

SDKをインストールする

developers.google.com

ありがたいことにGoogle SpreadsheetはJavaから操作できるインターフェイスを備えている。ScalaのSDKは存在していないようなので、これを操作することにした。

sbtに依存関係を書き込み、インストールする。

lazy val googleApiClient = "com.google.api-client" % "google-api-client" % "1.30.4"
lazy val googleOAuthClient = "com.google.oauth-client" % "google-oauth-client-jetty" % "1.30.6"
lazy val googleSpreadSheetApi = "com.google.apis" % "google-api-services-sheets" % "v4-rev581-1.25.0"
// ...
libraryDependencies ++= Seq(googleApiClient, googleOAuthClient, googleSpreadSheetApi)

GCPのコンソールでアプリと認証情報を作る

あらかじめGCPのコンソールでアプリを作成し、OAuthの準備をする。といっても、アプリ作成後に行うのは次の2つ。

  • OAuth認証情報を作成する
  • OAuth認証画面を設定する

f:id:Windymelt:20210624204309p:plain

この2つを設定すればよい。デスクトップアプリケーションという体裁で設定を行った。アプリケーション自体の作成方法は、ここでは割愛。

デスクトップアプリケーションという体裁なので、初回利用時にはブラウザが開いてOAuth認証画面が許可を求めてくる。完全ヘッドレスだとちょっと難しいのではないかと思う。 完全ヘッドレスにしたければAPIキーみたいなものを作成することになるのだろうか。今回はブラウザで我慢することにした。

developers.google.com

このリンクを参考にクレデンシャルをダウンロードして、プロジェクトの好きな箇所にcredentials.jsonという名前で保存しておく。たぶんリポジトリにチェックインしてはいけないファイルだと思う。

コーディング

やることは簡単。まずクレデンシャル情報を取得し、OAuth認証を突破してトークンを獲得し、そのトークンを使ってAPIを操作するのだ。

クレデンシャルの取得 && OAuth実行

github.com

クレデンシャル取得まわりはここにまとめた。getCredentialを呼ぶとOAuth認証が開始され、ユーザはブラウザに飛ばされて認証を要求される。

Spreadsheet APIを叩く

github.com

実際にシートにデータを入力する箇所はシンプル。元がJavaのAPIなのでBuilderパターンがたくさん出現するが、まあ我慢するしかない。

これで、 writeRange("....", "sheet!A1:p100", Seq(Seq(...)...)) というふうに呼べば、好きなシートの範囲を更新できるようになる。

最上位

App.scalaは、基本的にSpreadsheetのIDなどを設定ファイルから読み出して渡すだけ。

github.com

import Config.config
// ...
implicit val credential = spreadsheet.CredentialFactory
 .getCredential(
  config.getString("google.credentialsPath"),
  config.getString("google.tokenPath")
 )
 .get
// ...
spreadsheet.SpreadSheet.writeRange(
 config.getString("google.spreadsheetId"),
 config.getString("google.spreadsheetRange"),
 rows // Seq[Seq[String]]
)

reference.conf / application.conf

reference.confは以下のようになっている。

// ...
google {
    tokenPath = "token"
    credentialsPath = "credentials.json"
    spreadsheetId = ""
    spreadsheetRange = ""
}

ここで歯抜けになっている箇所をapplication.confで設定する(割愛)。これまでは環境変数でいちいち設定していたのだが、これでファイルに押し込むことができた。ちなみに環境変数を書くこともできるはず。

github.com

実行

普通に走らせるだけ。

% sbt run

するとブラウザが開いておなじみの承認画面が登場する。許可するとSpreadsheetにデータが書き込まれるはずだ。

感想

実行してみると、前回の記事で作成したデータを無事Spreadsheetに転記することができたので嬉しい。データの取得と書き込みが自動化できたので、バーンアップチャートを定時更新したりできるようになった。application.confの秘匿性の問題や、OAuth2のトークン情報をどうするかといった問題があるものの、もうひと頑張りすればクラウド環境にのっけて自動実行できるようになりそうだなと思った。

Spreadsheetへの書き込みは汎用性が高い技術なので、うまく活かしたい。

★記事をRTしてもらえると喜びます
Webアプリケーション開発関連の記事を投稿しています.読者になってみませんか?