🌇

NuxtでスプレッドシートをDB代わりに使うぞ大作戦 Part2 - モバイルだって使いたい!

4 min read

こんにちは。@asatoです☀

[前回の記事]

https://zenn.dev/at946/articles/0c170df6a5a16b

前回の記事で、見事NuxtでスプレッドシートをDB代わりに使うことに成功しました🎉🎉🎉

そう...PCでは...

実際にngrokとかで試していただくとわかるのですが、この方法だとモバイルからアクセスしたときに機能しません。
少なくとも僕のiPhone8 + Chrome構成ではアクセスできません...

今開発しているspaces.bzでも、ローカル開発で自動テストも通ってリリース!としたらモバイルでアクセスできず「ぐぬぬ」となったのはよい思い出。

ということなので、モバイルでもスプレッドシートのデータを表示するぞ!!!💪

何がだめなの?

PCでできてモバイルでできないとは何事か。一体何が起きているのでしょう。
axiosでエラーハンドリングしてみると、モバイルでは「Error: Network Error」と表示されます。こいつだ!👮

「axios network error mobile」「axios network error gas」など色々検索してみると、どうやらCORS周りが怪しいようです。
簡単に言えばAccess-Control-Allow-Origin*とかを設定するのではなく、ちゃんとOriginを設定しろとのこと。
が、GASはヘッダー情報をいじれない...

ということで、jsonpを利用してCORSを回避する方法が情報としては多かったです。

今回はJSONPで情報を取得できるようにしてみます。

やること

  • Nuxtのデータ取得をJSONPバージョンに更新
  • GASのレスポンスをJSONPバージョンに更新

Nuxtの更新

まずはNuxt側の更新をしていきます。最初にaxiosの中でjsonpを使えるようにしてくれるaxios-jsonpを導入します。
ちなみにaxios自体はjsonpをサポートしていないようです(axios/COOKBOOK.md at master · axios/axios)。

$ yarn add axios-jsonp

axiosのオプションにadapterとして指定します。

pages/index.vue
  ...
  <script>
+   const jsonpAdapter = require('axios-jsonp')
+
  export default {
    data() {
      return {
        users: []
      }
    },
    created() {
      this.getUsers()
    },
    methods: {
      async getUsers() {
-       this.users = await this.$axios.$get('/api')
+       this.users = await this.$axios.$get('/api', { adapter: jsonpAdapter })
      }
    }
  }
  </script>

Nuxt側の準備はこれで以上です。👏

次は、GASを更新します。

GASの更新

JSONPが何者かっていうと、JSONをCallback関数の引数として返すものです。

通信のイメージは

  • リクエスト側:このCallback関数にデータちょうだーい
  • レスポンス側:データをCallback関数の引数にして送るよー
  • リクエスト側:ありがとー。あとはこっちのCallback関数で処理するぞー

axios-jsonpはリクエスト側の「callback関数を自動で生成する」「axiosっぽくcallback関数で処理する」などをやってくれるライブラリということですね。

なのでGAS側もその挙動に合わせてコーディングし直します。更新する箇所はコード.jsdoGet関数の部分だけです!

コード.js
- function doGet() {
+ function doGet(e) {
    const users = getUsers()
+   const callback = e.parameter.callback

    return ContentService
-     .createTextOutput(JSON.stringify(users))
-     .setMimeType(ContentService.MimeType.JSON)
+     .createTextOutput(`${callback}(${JSON.stringify(users)}))
+     .setMimeType(ContentService.MimeType.JAVASCRIPT)
  }

以上です。ちょっと説明。

function doGet(e) {

doGet関数は引数eを利用可能です。eventですね。ここからURLのクエリパラメーターを取得できたりします。

https://developers.google.com/apps-script/guides/web?hl=en#request_parameters

axios-jsonpはクエリパラメーターcallbackでcallback関数を指定してくれるので、それを取得してレスポンスで返却するためにeを追加します。

const callback = e.parameter.callback

こんな感じ。

.createTextOutput(`${callback}(${JSON.stringify(users)})`)

この部分でcallback([{'id': '1', ...}, ...])みたいなレスポンスを生成しています。
これをaxios-jsonpが受け取っていい感じにデータ[{'id': '1', ...}, ...]を扱ってくれるんですね。

.setMimeType(ContentService.MimeType.JAVASCRIPT)

最後にJSONPはJSONとは異なり、MimeTypeをJAVASCRIPTにする必要があるので更新します。

以上でGASの更新も完了です。👏
WebAppをデプロイしてモバイルでもデータを表示できるか試してみましょう!

小噺:デプロイは「デプロイを管理」から

また新しいデプロイからWebAppを作成するとURLが前回から変わってしまいます。
「デプロイ」>「デプロイを管理」からバージョンアップがおすすめです。

デプロイを管理

まとめ

前回、スプレッドシートをDB代わりに使えるようになったかと思いきや、まさかのモバイルで使えない問題...
今回はJSONPを使うことでモバイルでもスプレッドシートのデータを表示できました!

これでPCでもモバイルでもデータを表示できたし一見落着...と思いきや...
spaces.bzでもこの方式でサービス提供していたのですが、いまは別のやり方にしてます。

次回!それSSRで動かしてよ

お楽しみに!

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

https://spaces.bz/

Discussion

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