シリーズ最終章です。
[前回の記事]

[前々回の記事]

Part2では、PCは表示できるけどモバイルはできない、というPart1の課題をJSON→JSONPに更新することで解決しました🎉。
これでOKかと思いきや、spaces.bzの開発では次なる課題が現れました。
- 動的OGPやりたいよね
- Search Consoleでソフト404って出てるけどなんだろうね
うむ。いまのデータはcreated
で取得しているのですが、ロボットに情報を確認してもらうためにはasyncData
でデータを取得しないとですね。
たとえば、spaces.bzのデイリーランキングページを見てください。 このページでは動的OGPやソフト404対策としてアクセス時はasyncData
を使ってスプレッドシートからデータを取得しています。 また、日付の変更の場合はmethods
の関数を使ってスプレッドシートからデータを取得しています。
Part2の内容を踏まえると、asyncData
でも同じようにデータを取得しようとすれば実現できそうですよね。 (ボタンを押したらデータを更新する感じにします)
<template> <div> <button @click="getUsers">更新</button> <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> const jsonpAdapter = require('axios-jsonp')
export default { async asyncData({ $axios }) { const users = await $axios.$get('/api', { adapter: jsonpAdapter })
return { users: users } }, data() { return { users: [] } }, created() { this.getUsers() }, methods: { async getUsers() { this.users = await this.$axios.$get('/api', { adapter: jsonpAdapter }) } } }</script>
よし、これで行けるはず。
まあ、これで大丈夫なら記事書かないんですよね。
ということで、今回はasyncData
でもスプレッドシートをDB代わりに使おう大作戦です。
何がだめなの
なにが起きてるかというと、axios-jsonp
でエラーが発生しています。 「document is not found」とか「window is not found」とか、このエラーはフロントエンドで動作する前提のパッケージがバックエンドで動作するときに起こります。 つまり、asyncData
はバックエンドでデータを取得するので、フロントエンドで動作する前提のaxios-jsonp
は利用できないのです。
じゃあどうする
こういうパッケージはnuxt.config.js
でssr: false
する、<no-ssr>
、<client-only>
タグで囲む、などの解決策が提示されています。 しかし、今回はasyncDataで動作させたいので採用できません。 かといって、何も考えずにJSONPをやめてしまえばまたモバイルで使えなくなる...。
ということでserverMiddleware
を使ってみましょう。 いままで「フロントエンド」→「GASのWebApp」と通信していた間にBFFのようにserverMiddlewareが入ります。 これによって、フロントエンドとしては同じドメインのサーバーと通信しているようになるのでCORS対策もバッチリになります。
モバイルで使えないってなったとき、JSONP
じゃなくてserverMiddleware
でもよかったのですが当時は気づきませんでした。
NuxtアプリでserverMiddleware経由でGAS APIをコールする
まずはBFFでGAS APIをコールするコードを書いていきましょう。 ここでは express
を利用します。
yarn add express
新しくapi
ディレクトリを作成し、その中にBFFのコードを書いていきましょう。
mkdir apitouch api/index.js
const express = require('express')const axios = require('axios')
const app = express()
app.get('/', async (req, res) => { const users = await axios.get(<ウェブアプリのURL(GAS API)>) res.send(users.data)})
module.exports = { path: "/api/", handler: app}
今までpages/index.vue
でやっていたaxios
の処理を転記した感じですね。 これをnuxt.config.js
にserverMiddleware
として登録しましょう(ついでにproxyも不要になったので消します)。
export default { ... axios: { proxy: true }, proxy: { '/api': { target: <ウェブアプリ(GAS API)のURL>, pathRewrite: { '/api': '' } } }, serverMiddleware: [ '@/api/' ], ...}
これでserverMiddleware
の準備は完了です。
フロントエンドもJSONP
からJSON
を取得するように更新しておきましょう。
...<script>const jsonpAdapter = require('axios-jsonp')
export default { async asyncData({ $axios }) { const users = await $axios.$get('/api', { adapter: jsonpAdapter }) const users = await $axios.$get('/api')
return { users: users } }, methods: { async getUsers() { this.users = await this.$axios.$get('/api', { adapter: jsonpAdapter }) this.users = await this.$axios.$get('/api') } }}</script>
axios-jsonp
も不要になったので、パッケージを削除しておきましょう。
yarn remove axios-jsonp
見ての通り、JSONP
ではなくJSON
を期待してのコールですので、GASのコードを元(Part1)時点に戻していきます。
GAS APIをJSON返却に戻す
function doGet(e) { const users = getUsers() const callback = e.parameter.callback
return ContentService .createTextOutput(`${callback}(${JSON.stringify(users)})`) .setMimeType(ContentService.MimeType.JAVASCRIPT) .createTextOutput(JSON.stringify(users)) .setMimeType(ContentService.MimeType.JSON)}...
ここまででBFFの準備ができました🎉。
動作確認
最後に動作確認をしておきましょう。 期待動作は次の通りです。
http://localhost:3000/
にアクセス → ユーザーA/B/Cのデータが表示される- SpreadsheetにユーザーDのデータを登録
- Nuxtの方で「更新」ボタンを押す → ユーザーDのデータも表示される
ではやっていきましょう。
1. http://localhost:3000/
にアクセス
表示されてる。
2. スプレッドシートにユーザーDを追加
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 |
4 | Test D | 50 | test_d@sample.com |
3. 更新ボタンを押下
ユーザーDの情報が新たに表示されてる。
テスト成功🎊。
まとめ
今回はserverMiddleware
を使って、スプレッドシートをDB代わりに使ってみました。 ここまで色々と試行錯誤をしてきましたが、今回の方法はやりたいことができる中で一番手っ取り早い方法でしょう。 Google Sheet API とかも試みてみましたが挫折しました...。
スプレッドシートだとデータも見やすいですし、GASで色々操作できるので、作りたいプロダクトによっては1つの選択肢になってきそうです。 この記事が、どなたかの役に立てば嬉しいです。
サポートもお待ちしております!