はじめに
最近バックエンドのコードを書く機会が減り、代わりにFirebaseを利用する機会が本当に増えてきました。
本投稿はSPA(Nuxt.js)で実装したものをFirebase上で動かすにあたって、Hello Worldから毛が生えアプリが成長し複雑になっていく過程で、つまずいた体験の紹介になります。
1.動的なルーティングが動かなくて、つまずいた
Nuxt.jsでgenerateしてdistディレクトリをFirebase Hostingにdeployすれば、できたできたヤッターとなります。
ですが、動的なルーティング1は単純にそれだけだとFirebase Hosting上では動きません。
とりあえずサクッと対応したいという場合はhashモードにかえましょう。
router: {
mode: 'hash',
},
2.Functionsで作ったREST APIがローカルから呼べなくて、つまずいた
const functions = require('firebase-functions');
exports.getSample = functions.https.onRequest(async (request, response) => {
res.json({success: true, date: (new Date()).getTime() });
});
こんな感じで作成したFunctionsをdeployすれば
https://us-central1-[PROJCECT_ID].cloudfunctions.net/getSample
というURLのREST APIができます。ブラウザで試しにアクセスすると、正しくJSONが出力されることが確認できました。
それではこれをクライアントから呼び出してみますが、
return axios({
method: 'GET',
url: 'https://us-central1-[PROJECT_ID].cloudfunctions.net/getSample',
})
こうして、yarn dev
からのhttp://localhost:3000
での動作確認なんてことをしちゃうとエラーになってしまいます。
これは単純なCORSによるエラーなので、対応としては
proxy: {
'/functions_api': {
target: 'https://us-central1-[PROJECT_ID].cloudfunctions.net',
pathRewrite: {
'^/functions_api': '/',
},
},
},
return axios({
method: 'GET',
url: '/functions_api/getSample',
})
とすれば、http://localhost:3000
での動作確認もうまくいくようになります。
ちなみに上記proxy
を変更すれば向け先をEmulatorで動かしているFunctionsにすることも可能ですね。
そんなこんなで開発は進行し、さらに修正して
const currentUser = firebase.auth().currentUser
if (currentUser) {
const token = await currentUser.getIdToken()
return axios({
method: 'GET',
url: '/functions_api/getSample',
headers: { Authorization: `Bearer ${token}` },
})
}
const admin = require('firebase-admin');
const functions = require('firebase-functions');
admin.initializeApp();
exports.getSample = functions.https.onRequest(async (request, response) => {
const token = req.headers.authorization.split('Bearer ')[1];
const decodedToken = await admin.auth().verifyIdToken(token);
// decodedToken.uidを用いて適切なアクセス制限実行
res.json({success: true, date: (new Date()).getTime() });
});
Firebase Authenticationを通過しているユーザのみアクセス可能にする、という実装に変えました。
3.Functionsで作ったREST APIが本番Hostingから呼べなくて、つまずいた
2の修正後に、generateしたものをFirebase Hostingにdeployして動作確認してみました。
なんということでしょう、またREST APIが呼び出せていません。ブラウザのデバッガーで確認すると
GET https://[PROJECT_ID].web.app/functions_api/getSample 404
こんなエラーが出ています。え?404?、、あーこのURLにアクセスしちゃうのね。。
ということで、firebase.jsonでrewritesを追記しました。
"hosting": {
"public": "dist",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "/functions_api/getSample",
"function": "getSample"
},
},
},
これにて、本番Hostingでも正常にアクセスできるようになりました!ヤッター!
(おまけ)Functionsで作ったREST APIが重くて、つまずいた
せっかく上記2と3を乗り越えて作ったものの、やたらレスポンスが遅いのが気になってしまいました。
重くてもしょうがない性質な処理でもあったので、高速化を試みるのではなく、処理の最初の方で、res.json()
によりレスポンスだけササッと返して、裏でゆーっくりと処理しておいてくんないかなと思ったものの、上手く行かず。。。
そこで、HTTPリクエストトリガーでの実行をやめ、Cloud Firestoreトリガーに変更して、クライアント側からはFunctionsへのキュー的な指示のためのデータをFirestoreにsetするというやり方に変えてみました。
すると、上記であった「Authenticationを通過しているユーザのみアクセス可能に」を考えなくてすむし、責任分界点がはっきりして開発効率悪くないし、これはこれで案外いいかもな〜って思ったりもしました。
おしまい
ではでは、皆様メリクリ〜
-
pages
配下に_id.vue
のようなアンスコ始まりのファイルを設置して、this.$route.params.id
で値が参照できるNuxtの機能。(参考:ファイルシステムに基づくルーティング) ↩