2021年9月28日

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

読了時間の目安: 4分


[前回の記事]

NuxtでGoogle SpreadsheetをDB代わりに使うぞ大作戦 | at-blog

前回の記事で、見事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 - npm

ちなみにaxios自体はjsonpをサポートしていないようです。

axios/COOKBOOK.md at main · axios/axios · GitHub
Terminal window
$ 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関数の引数として返すものです。

第11回 JSONP入門 | gihyo.jp

通信のイメージは以下のとおりです。

  • リクエスト側:この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))
.createTextOutput(`${callback}(${JSON.stringify(users)})`)
.setMimeType(ContentService.MimeType.JSON)
.setMimeType(ContentService.MimeType.JAVASCRIPT)
}

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

function doGet(e) {

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

Web Apps  |  Apps Script  |  Google for Developers

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でもこの方式でサービス提供していたのですが、いまは別のやり方にしてます。

続編

NuxtでスプレッドシートをDB代わりに使うぞ大作戦 Part3 - asyncDataでだって使いたい! | at-blog
  • 名前:asato
  • 仕事:スクラムマスター
  • 好き:家族、温泉、旅行、謎解き
  • 苦手:はじめまして、あんこ、うなぎ