Go言語でGoogle Cloud SDKを使うときApplication Default CredentialsのJSONファイルをパスではなく文字列で渡す方法

状況

Google Cloud Vision APIをGo言語で使うとき、公式のライブラリがあったのでそれを使っていたら、どんなAPIを叩くにもApplication Default Credentialsが必要だという。Vision APIREST APIから直接叩くにはAPI Keyだけで良いというのに、ライブラリを使うならService Accountが必要。わけわからん(実はライブラリ/依存ライブラリのソースの至るところに"This API is Beta"と書いてあるので今後変更される可能性がある)。

プルリク送ろうとも思ったが、膨大すぎて読みきれなかった/設計の意図を汲み取りきれなかったために断念。おとなしくService Accountを使うことにしたが、Herokuで運用する予定のためJSONファイルをリポジトリ内に置くのはNG。実は先のURLに書いてあるとおり、Application Default CredentialsはキーのJSONファイルのパスを環境変数として指定する方法しかサポートしていない。これは困った。さすがに環境変数で文字列を受け取りそれをファイルに書き込んでからパスで指定するとかしたくない。と思い4時間ソース読んだり試行錯誤したりした先で、やっとこのStack Over Flowを見つけた。

Load GOOGLE_APPLICATION_CREDENTIALS json content via an environment variable instead of a file · Issue #185 · google/google-api-go-client

このページに(ほぼ)内部APIを使ってJSONを変数から読み込みパースし、TokenSource(内部で使われる認証情報を含む構造体)を作るコードが載ってる。

これを参考に(ほぼそのまんまだけど)以下のような感じでいけた。

json := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS_JSON")
ctx := context.Background()
jwtConfig, err := google.JWTConfigFromJSON([]byte(json), vision.Scope)
if err != nil {
    fmt.Println(err)
}
ts := jwtConfig.TokenSource(ctx)
visionClient, err := vision.NewClient(ctx, option.WithTokenSource(ts))