スプレッドシートをデータベースとして活用する方法をまとめます。
いま話題のTwitterスペースと出会えるプロダクトspaces.bz(クローズ済み)を開発しています。
GASでTwitter APIをたたいてスプレッドシートに記録するプロトタイプからはじめました。 プロトタイプのあと、このままスプレッドシートをDBとして使えれば楽なのではと考え、Nuxt + Spreadsheet構成でプロダクトを開発してみたので、体験記をまとめます。
この記事でやること
スプレッドシートからデータを取得して表示するNuxtアプリを作ります。 サンプルのスプレッドシートは次のようなイメージ。
| id | name | age | |
|---|---|---|---|
| 1 | Test A | 20 | test_a@sample.com |
| 2 | Test B | 30 | test_b@sample.com |
| 3 | Test C | 40 | test_c@sample.com |
スプレッドシートをJSONで返却するGASを作成
まずはスプレッドシートの情報を取得するAPIみたいなものを作っていきます。 GASでプログラムを組んでWebアプリとして公開する、をしますが、GASの方からやっていきます。
function doGet() { const users = getUsers()
return ContentService .createTextOutput(JSON.stringify(users)) .setMimeType(ContentService.MimeType.JSON)}
function getUsers() { const ss = SpreadsheetApp.openById('スプレッドシートのID') const sheet = ss.getSheetByName('シート名') const rows = sheet.getDataRange().getValues() const keys = rows.splice(0,1)[0]
const users = rows.map((row) => { const object = {} row.map((value, index) => { object[keys[index]] = value }) return object })
return users}ちょこっとコードをみてみます。
doGet関数
このコードの最初の肝はdoGet関数を用いていることです。 この後Webアプリで公開すると話しましたが、doGet関数はWebアプリで公開したURLにGETリクエストが来たときに動く関数です。
今回のコードではdoGet関数が動き出したらgetUsers関数を呼び出してスプレッドシートの中身をJSONに整形し返却します。
return ContentService .createTextOutput(JSON.stringify(users)) .setMimeType(ContentService.MimeType.JSON)getUser関数
次に、getUser関数をみてみます。
const ss = SpreadsheetApp.openById('スプレッドシートのID')最初に対象のスプレッドシートを読み込んでいます。スプレッドシートのIDはスプレッドシートのURLからわかり、https://docs.google.com/spreadsheets/d/*****/editの*****の部分です。
const sheet = ss.getSheetByName('シート名')次に、そのスプレッドシートのシート名のシートを持ってきます。
const rows = sheet.getDataRange().getValues()そして、そのシートのデータが入力されているセルのデータを行単位の配列で取得します。 サンプルの例だと、rowsの値は次のようになっています。
rows = [ ['id', 'name', 'age', 'email'], ['1', 'Test A', '20', 'test_a@sample.com'], ['2', 'Test B', '30', 'test_b@sample.com'], ['3', 'Test C', '40', 'test_c@sample.com']]const keys = rows.splice(0,1)[0]お次はrowsの1つ目の配列を取り出してkeysに代入しています。これによって、keys、rowsは次のようになります。
keys = ['id', 'name', 'age', 'email']
rows = [ ['1', 'Test A', '20', 'test_a@sample.com'], ['2', 'Test B', '30', 'test_b@sample.com'], ['3', 'Test C', '40', 'test_c@sample.com']]これでkeysがjsonのkeyになり、rowsに残った項目がvalueになる未来が見えてきました。
const users = rows.map((row) => { const object = {} row.map((value, index) => { object[keys[index]] = value }) return object})そんな未来を実現するコードがこれです。 rows.map((row) => { 処理 })でrowsから配列を一つずつ持ってきて変数rowに格納し処理を実行しています。 処理の部分でもrow.map((value, index) => { 処理2 })としてrowの要素を一つずつ取り出します。 処理2でobject[keys[index]] = valueとすることで各配列をオブジェクトの形に整形しています。
最終的にusersの値はこんな感じです。
users = [ { id: 1, name: 'Test A', age: 20, email: 'test_a@sample.com' }, { id: 2, name: 'Test B', age: 30, email: 'test_b@sample.com' }, { id: 3, name: 'Test C', age: 40, email: 'test_c@sample.com' }]これを最後にreturnする関数です。
これでWebアプリを公開したときにスプレッドシートのシートをjsonで返却するGASの準備ができたので、次はWebアプリを公開していきます。
Webアプリを公開する
WebサイトはGASのエディターの上部にある「デプロイ」ボタンから行います。

「デプロイ」>「新しいデプロイ」を選択して...。

「種類の選択」>「ウェブアプリ」を選択して...。

「新しい説明文」にわかりやすい名前(productionとかtestとか)、「次のユーザーとして実行」に「自分」を、「アクセスできるユーザー」に「全員」を設定し、「デプロイ」を選択して...。

(必要な場合は)「アクセスを承認」を選択して...。

「Google認証」して...。

「Advanced」を選択して、「<プロジェクト名>(unsafe)」を選択して...。

「Allow」して...。

完了です🎉。 「ウェブアプリ」の方に書いてあるURLがAPI(サイトとしても)公開しているURLになります。ちょっとcurlしてみましょう。
$ curl -L <URL>
[ {"id":1,"name":"Test A","age":20,"email":"test_a@sample.com"}, {"id":2,"name":"Test B","age":30,"email":"test_b@sample.com"}, {"id":3,"name":"Test C","age":40,"email":"test_c@sample.com"}]返却されていますね。
画面じゃないとわかりにくいなと思い、画像多めでお届けしました。 ってことなので、これをNuxtでの表示を作っていきます。
NuxtでAPI叩いて表示
最後に、今公開したAPIをNuxtアプリから叩いてデータを表示していきます。
まず、APIを叩くために @nuxtjs/axios を導入してきます。
yarn add @nuxtjs/axiosnuxt.config.jsでモジュール登録もしてきましょう。
export default { ... modules: [ '@nuxtjs/axios' ], ...}axiosはCORS対策もしっかりしてくれているので、このままでは先程作ったウェブアプリのAPIを叩けません。 そこで、proxyします。
export default { ... modules: [ '@nuxtjs/axios' ], axios: { proxy: true }, proxy: { '/api': { target: <ウェブアプリのURL>, pathRewrite: { '^/api': '' } } }, ...}これで、内部の/apiにaxiosでデータ取得しようとするとCORS対策を迂回してウェブアプリのAPIを叩くことができます。 ちょうど、このURLは信頼できるURLだよ、と登録しているような感覚ですね。
これでウェブアプリのAPIを叩く準備が整ったので、ページを作成していきます。
<template> <div> <table> <thead> <tr> <th>id</th> <th>name</th> <th>age</th> <th>email</th> </tr> </thead> <tbody> <tr v-for='user in users' :key='user.id'> <td>{{ user.id }}</td> <td>{{ user.name }}</td> <td>{{ user.age }}</td> <td>{{ user.email }}</td> </tr> </tbody> </table> </div></template>
<script>export default { data() { return { users: [] } }, created() { this.getUsers() }, methods: { async getUsers() { this.users = await this.$axios.$get('/api') } }}</script>ちょっと長いですが、templateの方はtableとv-for使っているだけなので説明は省略です。
重要なのはscript側ですね。 今回はmethodsでgetUsers()をasync-awaitで記述し、createdで呼び出してます。getUsers()は、axiosを使ってウェブアプリAPIからスプレッドシートのデータを取得して、this.usersにデータを代入してます。
これでページにアクセスしてみると...。

スプレッドシートと同じ情報を表示できていますね🎉🎉🎉。
まとめ
今回はスプレッドシートをDB代わりに使えないかなー、ということで以下をやってみました。
- GASのウェブアプリを使ってスプレッドシートの情報を返却するAPIを作ってみた
- NuxtアプリでそのAPIを使ってスプレッドシートの情報を表示してみた
それぞれいろいろな参考記事を書いてくださっている方々がいらっしゃったんですが、あわせ技のところで困ったりしたので一連通してやるとこうなるぞという記事を書いてみました。 これですべてが上手くいった...そう思っていたのですが...。
次回、モバイルでもそれ動くのか
お楽しみに😆...😢。
続編を公開しました。
サポートもお待ちしております!