Open15

Google SheetsからJSONを出力する方法の数々

Richard ImaokaRichard Imaoka

アプリケーション開発のごく初期段階において、データ管理にデータベースではなくGoogle Sheetsを用いると開発速度をあげられる可能性があります。

Google Sheetsを暫定的なデータベースとして使うことで、データベースの導入に伴うデータモデリングやテーブル設計に時間を費やすことなく、手早くユーザー体験を検証できるからです。さらにGoogle Sheetsを使えば、営業職や経理職、オペレーション担当といった人たちでも手軽にデータ更新でき、エンジニアが介在する必要性が下がります。

Google Sheets内のデータそのままではアプリケーション内で使いづらいので、ここではいったんJSONに出力する方法を考えていきましょう。

Richard ImaokaRichard Imaoka

Google SheetsのデータをJSONで出力するには様々な方法があります。下の画像に載っているもので、主要な選択肢は網羅できているはずです。

この図の左は簡単で右は難しくなっていくので、初期開発からはじめて、だんだん開発進むに連れ少しずつ右側の選択肢を検討すると良いと思います。全てを順番に試す必要はありません。

左側の選択肢ほど、簡単で導入の手間はかかりませんが、複雑なデータ構造に対しては柔軟性が足りません。またデータ更新があまりに頻繁だとJSON出力のたびに複数回クリックが必要なので面倒に感じてしまいます。

右に行くほど導入は難しく大変ですが、データ加工も自由自在で、Google Sheets側でのデータ更新を即座にアプリケーション側に反映することも可能です。

Richard ImaokaRichard Imaoka

選択肢1: CSV→JSON変換サービスを利用

選択肢1-1: 既存のオンライン変換サービス

すでに世の中には https://csvjson.com のような変換Webサービスがあるので、それを利用するのが、開発の手間がかからないという意味では一番楽な方法です。

https://youtu.be/OvRlrJGQuK4

ただし、この方法だけでは満足できない場合もあります。例を上げると

  • 会社の方針でGoogle Sheets上の機密データを外部Webサービスに送信できない
  • Google Sheetsを頻繁に更新し、そのたびにJSONに手作業で変換するのが面倒
上記2点の補足
  • 1点目について、例えば https://csvjson.com/Any data pasted and converted on csvjson remains local on your computer. Data is never sent to the server. となっていますが、それでも会社の方針として認められない場合もあると思います。
  • 2点目は、面倒に「感じる」だけで、一回あたりの変換作業は15秒くらいで済むので実際には問題ないかもしれません
    • それでも、更新するシートが多数ある、更新頻度が非常に高いといった場合はやはりいつまでも手作業で変換Webサービスを使い続けるのは難しくなってくるでしょう
Richard ImaokaRichard Imaoka

選択肢1-2: 自社内で独自の変換Webサービスを立ち上げる

上記で述べた、

会社の方針でGoogle Sheets上の機密データを外部Webサービスに送信できない

という問題を解決するための方法です。

選択肢1-1と同じ 「CSS→JSONへの変換」Webサービスと同じですが、それを自社内で開発し立ち上げます。そして自社の社員のみがアクセスできるようにします。

近年だとChat GPTやGemini、ClaudeなどAIサービスを使えばこれくらいすぐに書いてくれます。

プロンプト例
Go で Web サーバーを作成を作成してください。
ユーザーは CSV ファイルをアップロードし、
サーバーはそれを JSON ファイルに変換して、
ユーザーが自動的にダウンロードできるようにします。

https://www.youtube.com/watch?v=ynZBGaPW-as

AIが生成したコードの中身を確認する

最近のAIで生成したコードは、CSVからJSONへの変換をエラーを吐くことなく完了する、Webサーバーでファイルアップロードの機能をつける、といった程度なら初回のプロンプトを書くだけで、そのまま動く水準のコードが出力されます。だからといって、そのままのコードを採用していいかとは限りません。そのまま採用するにしても、コードの中身を確認してからにしましょう。

たとえば、私が上記の動画のデモ用に生成したコードでは、以下のような値の変換が行われていました。これが適しているか、不適当化は場合によって異なってきます。

// CSVの値を適切な型に変換する関数
func convertValue(value string) interface{} {
    // 空文字列の場合
    if strings.TrimSpace(value) == "" {
        return ""
    }
    
    // 数値(整数)として解析を試行
    if intVal, err := strconv.Atoi(value); err == nil {
        return intVal
    }
    
    // 数値(浮動小数点)として解析を試行
    if floatVal, err := strconv.ParseFloat(value, 64); err == nil {
        return floatVal
    }
    
    // ブール値として解析を試行
    if boolVal, err := strconv.ParseBool(strings.ToLower(value)); err == nil {
        return boolVal
    }
    
    // それ以外は文字列として返す
    return value
}
Richard ImaokaRichard Imaoka

選択肢1-2における認証

自社内で独自の「CSV→JSON変換Webサービス」を立ち上げる場合、社内の人間のみがアクセスできるように、認証の仕組みが必要です。

変換Webサービスにアクセスする社員が全員Googleアカウントを持っている場合「Google で​ログイン」(英語名 Sign in with Google) を利用するのが一番楽かなと思います。

https://www.youtube.com/watch?v=kc_aLQdbrS4

ただし他の選択肢でも全く問題なく、Firebase AuthでもAuth0でも信頼できる会社から提供されていて、自分が使いやすいものを使えばいいと思います。

Richard ImaokaRichard Imaoka

選択肢1-1および1-2でのエッジケース (期待に反するデータ)

単純にGoogle SheetsからCSV形式でダウンロードするだけでは、CSVファイルの中に思わぬデータが紛れ込んでしまうことがあります。

たとえば、値段が「¥4,950」と表示されていたとして、

4950という数値を表示形式によって「¥4,950」にしている場合は問題ないのですが、そうではなく実際に¥4,950という文字列になっていたなら、このようなCSVがダウンロードされてしまいます。

日付,商品,値段
2024/08/21,Tシャツ赤,"¥4,950"

JSONへの変換、その後のアプリケーション内での利用を考えると4950という数値のほうが扱いやすいので¥という文字が入ったままでは困ってしまいます。

こういった期待に反するデータがCSVとして出力されてしまうエッジケースを考えると、次に紹介する選択肢2のGoogle Apps Scriptを使った手法のほうが、プログラミングスキルを要求されハードルが高い反面、ちょっとしたデータ加工を行える柔軟性があるので、期待通りのデータを出力しやすくなるでしょう。

Richard ImaokaRichard Imaoka

選択肢2: Google Apps Scriptを使う

Google Apps ScriptでJSONをログ出力する方法です。

選択肢2-1: ログにJSONを出力

https://www.youtube.com/watch?v=zEMgzfAyL3w

動画にもあるように、私が試したときはGoogle Sheets上のGeminiがGoogle Apps Scriptを書いてくれなかったので、(追記: 場合によっては書いてくれるみたいです。書いてくれる条件は私では解明できませんでしたが。)Gemini web app https://gemini.google.com/app に頼んでみました。

Richard ImaokaRichard Imaoka

選択肢2-2: Google Apps Script: Google Drive保存

先ほどのGoogle Apps Scriptでログ出力する方法では、JSONが大きすぎるとログが途中で切れて不完全なJSONになってしまいます。この問題はGoogle DriveにJSONファイルとして出力すれば解決できます。

https://www.youtube.com/watch?v=EDrt0PZNP0Q

Richard ImaokaRichard Imaoka

選択肢2-3: Google Apps ScriptのWeb App

Google Apps Scriptの興味深い機能として、doGetメソッド (もしくはdoPost)を実装するだけでweb app化できる、というものがあります。つまり、Google Sheets上のデータをJSON形式で表示するweb appも簡単に作成できます。

https://developers.google.com/apps-script/guides/web
Google Apps Script web app

https://www.youtube.com/watch?v=OhhL5pBmyaE

作成したweb appはhttps://script.google.com/macros/s/xxxxxxxxのようなURLで公開され、「アクセスできるユーザー」を「自分のみ」「Googleアカウントを持つ全員」「全員」(※英語だとanonymous)から選べます。適切に公開範囲を選べば社内の人間だけがアクセスできるweb appになるので、先述の社内でサーバーを立てる選択肢の代わりになります。(ただしGoogle Apps Scriptを書くので、それを理解できることが条件です。)

Google Apps Scriptでちょっとしたデータ加工もできるので、単純にCSV出力→JSONに変換とするより、柔軟性が高くなるでしょう。

Richard ImaokaRichard Imaoka

Google Apps Scriptを使ってJSON出力を行えば、1シートにある複数のRangeからそれぞれJSONを出力する、複数シートからデータを結合して(SQLでいうJOIN)してJSONを出力する、といったこともできます。

前者はgetRangeByName()関数を使えば実現できます。すでに業務内で使われていてレイアウトが固定されており、シート内に複数Rangeを持つGoogle Sheetsブックを流用してJSONデータを出力する場合などに便利です。

後者はGoogle Apps Scriptなので、自由自在にデータを結合できます。最近であればAIにGoogle Apps Scriptを書いてもらい、実際のデータを見ながら手直しするのが早いでしょう。

Richard ImaokaRichard Imaoka

ちなみに Google Apps Script APIというものもありますが、これはApps scriptプロジェクトの操作を行うAPIで、Google Sheetsからデータを取得できず、今回の目的である「シート内のデータを取得してJSON出力」には使えません。

Richard ImaokaRichard Imaoka

選択肢3 Google Sheets API

選択肢2のGoogle Apps Scriptでもデータ加工やJOINなど、高度で柔軟なJSON出力は可能ですが、更にサーバーサイド開発と密接に結びつけて、サーバーサイドの開発言語でデータ加工を行う場合Google Sheets APIを利用できます。

直接REST APIを叩くよりは、Googleの提供する開発言語ごとのクライアント・ライブラリを使うとよいでしょう。

Google Sheets APIをサポートするクライアント・ライブラリは旧版であるGoogle API Client Librariesのみ

Google Sheets APIを含むGoogle Cloud API用のSDKには、2種類のライブラリCloud Client Libraries(新ライブラリ)とGoogle API Client Libraries(旧ライブラリ)があります。Google Cloud公式のClient libraries explained

A few Google Cloud APIs don't have Cloud Client Libraries available in all languages.

とあるように、残念ながらGooogle Sheets APIはGoogle API Client Libraries(旧ライブラリ)でのみサポートされているAPIです。

これも最近ですとAIに聞いてしまえば、すぐにソースコードを書いてくれます。以下のようなプロンプトで良いと思います。

Go言語のwebサーバーで、HTTPリクエストを受け取ったらGoogle Sheets APIを使ってデータを取得し、JSONに加工してHTTPレスポンスを返すサーバーを書いて

ただし、認証部分はAIが出力するソースコードを特に慎重に確認しましょう。ここは長くなるので次の項に書きます。

Richard ImaokaRichard Imaoka

選択肢3のGoogle Sheets APIでの認証

Google Sheets APIを使うソースコードをAIに書かせる場合、認証部分は特に慎重に確認しましょう。何も指定しないとGoogle Cloudサービスアカウントのキーを使って認証するソースコードが高確率で出力されますが、安全性を考えて代替手段での認証に変えるべきです。

Google Sheets APIもGoogle Cloudの一部という扱いですが、Google Cloudの認証は選択肢が非常に多くて、慣れない人は困ってしまうと思います。更に困ったことに、AIが出力するコードやさまざまな技術ブログでは、あまり安全でないとされるサービスアカウントの「キー」を使った認証を取り入れています。それが実装するうえでは簡単だからです。

サービスアカウントの「キー」における危険性

Google Cloud公式Service account credentialsより

Service account keys are commonly used to authenticate to Google Cloud services. However, they can also become a security risk if they're not managed properly, increasing your vulnerability to threats like credential leakage, privilege escalation, information disclosure, and non-repudiation.

In many cases, you can authenticate with more secure alternatives to service account keys. This guide helps you to migrate from using service account keys as your primary authentication mechanism to using more secure alternatives, with occasional exceptions where service account keys are truly necessary.

より安全な代替手法での認証を理解するには、公式ドキュメントGoogle Sheets API Overviewのすぐ下、Get Started配下にあるoverviewConfigure OAuth consentにある案内をじっくり読みながら、一つずつ進めていくしかありません。Google Cloudプロジェクト側での設定も必要になります。

Google CloudプロジェクトでのOAuth設定はなかなか面倒に感じるものですが、一度やってしまえば、ほとんど似たような手順を繰り返すことになるので、「ああ、またいつものあれか」と感じると思います。Google Cloud認証手法は多種あるのですが、基本は同じで、さすがにしっかりと設計されているなと思わされます。

ADC (Application Default Credentials)による認証

Google Cloudでの開発に慣れている人はADC (Application Default Credentials)による認証を検討してもいいと思います。

Google Sheets APIを使う場合、scopeを忘れずに指定しましょう。gcloud auth application-default loginコマンドの実行時に--scopesフラグGoogle Sheetsのscopeを設定指定できます。

たとえば https://www.googleapis.com/auth/spreadsheets.readonlyだと以下のようになります。--scopesフラグのデフォルト値も合わせて設定しています。

gcloud auth application-default login --scopes=openid,https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/sqlservice.login,https://www.googleapis.com/auth/spreadsheets.readonly
Richard ImaokaRichard Imaoka

選択肢4 Google Sheetsからデータベースへのシード

ここまで来るともはやJSON出力ではなくなってしまいますし、冒頭に述べた「データベースの設計をせずにすむ」というメリットもなくなってしまいますが、アプリケーション開発が進むに従ってここまでたどり着くケースもあると思うので記載します。

Google Sheetsからデータをシードする場合、営業職や経理職、オペレーション担当といったエンジニアでない人たちでも手軽にデータ更新できるメリットは残りますし、特に今まで本記事での選択肢1、2、3…のように段々と高度化してきたなら、スムーズな移行の選択肢になるでしょう。

他に考えられる、選択肢5を選ぶ理由

最近では直感的でわかりやすいデータベースクライアントが増えてきたので、がんばって説明すればエンジニアじゃない人たちでも触ってくれそうに思います。ただ、どうしてもGoogle Sheetsの扱いやすさには敵わないとも思います。

あるいは、クラウド上のデータベースSaaSを使っている場合、非エンジニアがDBデータベース操作をする時にちょっとしたデータ操作のためだけにユーザーアカウントを発行し、その分課金されるのは困るケースもあるかもしれません。

やり方としては

  • 選択肢5-1: Google Apps ScriptからHTTP呼び出しでSaaS上のデータベースにシード(選択肢3の応用)
  • 選択肢5-2: Google Sheets APIでデータ取得してデータベースにシードするスクリプトを書く(選択肢4の応用)

という感じかなと思います。

Richard ImaokaRichard Imaoka

選択肢5の実現方法として、Google CloudのEventarcでGoogle Sheetsから直接イベントを受け取ることもできるかな?と思いましたが、どうやらできないようです。