🌇

NuxtでスプレッドシートをDB代わりに使うぞ大作戦

2021/09/26に公開約6,700字

こんにちは。@asatoです☀

スプレッドシートをデータベースとして使いたい!
いま話題のTwitterスペースと出会えるプロダクトspaces.bzを開発しています。

https://spaces.bz/

GASでTwitter APIをたたいてスプレッドシートに記録するプロトタイプからはじめました。
プロトタイプのあと、「せっかくだからこのスプレッドシートをそのままDBみたいに使えないかなー」と思い、Nuxt + Spreadsheet構成でプロダクトを開発してみたので、体験記をまとめたいと思います!

この記事でやること

スプレッドシートからデータを取得して表示するNuxtアプリを作ります。
サンプルのスプレッドシートは以下のようなイメージ。

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

スプレッドシートをJSONで返却するGASを作成

まずはスプレッドシートの情報を取得するAPIみたいなものを作っていきます。
GASでプログラムを組んでWebアプリとして公開する、をしますが、GASの方からやっていきます。

コード.js
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リクエストが来たときに動く関数です。

https://developers.google.com/apps-script/guides/web

今回のコードではdoGet関数が動き出したらgetUsers関数を呼び出してスプレッドシートの中身をJSONに整形し、

return ContentService
  .createTextOutput(JSON.stringify(users))
  .setMimeType(ContentService.MimeType.JSON)

で、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に代入しています。これによって、keysrowsは以下のようになります。

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の要素を一つずつ取り出し、
処理2object[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アプリを公開する

https://developers.google.com/apps-script/guides/web#test_a_web_app_deployment

WebサイトはGASのエディターの上部にある「デプロイ」ボタンから行います。

デプロイ

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

新しいデプロイ

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

設定

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

認証

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

Google認証

「Google認証」して...

Continue

「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を導入してきます。

https://axios.nuxtjs.org/

$ yarn add @nuxtjs/axios

nuxt.config.jsでモジュール登録もしてきましょう。

nuxt.config.js
  export default {
    ...
    modules: [
+     '@nuxtjs/axios'
    ],
    ...
  }

axiosはCORS対策もしっかりしてくれているので、このままでは先程作ったウェブアプリのAPIを叩けません。
そこで、proxyします。

nuxt.config.js
  export default {
    ...
    modules: [
      '@nuxtjs/axios'
    ],
+   axios: {
+     proxy: true
+   },
+   proxy: {
+     '/api': {
+       target: <ウェブアプリのURL>,
+       pathRewrite: { '^/api': '' }
+     }
+   },
    ...
  }

これで、内部の/apiにaxiosでデータ取得しようとするとCORS対策を迂回してウェブアプリのAPIを叩くことができます。
ちょうど、このURLは信頼できるURLだよ、と登録しているような感覚ですね。

これでウェブアプリのAPIを叩く準備が整ったので、ページを作成していきます。

pages/index.vue
<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の方はtablev-for使っているだけなので説明は省略です。

重要なのはscript側ですね。
今回はmethodsgetUsers()async-awaitで記述し、createdで呼び出してます。getUsers()は、axiosを使ってウェブアプリAPIからスプレッドシートのデータを取得して、this.usersにデータを代入してます。

これでページにアクセスしてみると...

データ取得成功!

スプレッドシートと同じ情報を表示できていますね!!🎉🎉🎉

まとめ

今回はスプレッドシートをDB代わりに使えないかなー、ということで、

  • GASのウェブアプリを使ってスプレッドシートの情報を返却するAPIを作ってみた
  • NuxtアプリでそのAPIを使ってスプレッドシートの情報を表示してみた

をやってみました!
それぞれいろいろな参考記事を書いてくださっている方々がいらっしゃったんですが、あわせ技のところで困ったりしたので一連通してやるとこうなるぞという記事を書いてみました。
これですべてが上手くいった...そう思っていたのですが...

次回!モバイルでもそれ動くの?

お楽しみに!😆...😢

spaces.bzも応援よろしくおねがいします!

https://spaces.bz/

続編を公開しました!
https://zenn.dev/at946/articles/bfd9d500359427

Discussion

ログインするとコメントできます