Firebase AdminはFirebaseに関するサービスをプログラムを通して操作できるようにするものです。
Firebase Adminはサーバでしか動かない
Firebase Adminを使ってFirestoreのデータを操作したいことってよくあると思います。
Firebase公式サイトから直接FireStoreデータベースを見ることができますが、正直な話使いやすいものではありません。また、FireStoreの管理画面から、並べ替えや検索といったクエリは一切使えません。例えば「有料会員だけ表示したい」といったことができないのです。
そういった「高度な」操作をしたい場合は今回のテーマでもある「Fireabse Admin」を使えば解決です。Firebase Adminは普段、システム開発で利用している Firebase APIと同じように使えます。しかし、なんとFirebase Adminはサーバでしか動作しないという問題があります。
サーバ上でしか動かないならサーバを用意するしかないね。Expressで行こう
有料会員の一覧を出したいだけなのに、いちいちサーバを用意するのは非常に気が引けますが、Expressを使えば超お手軽サーバが用意できます。Firebase AdminをExpress上で動かし、フロント回りはVue.jsで実装します。
バックエンドもフロントも、javascriptに統一できるのは個人的に好きです。
// [index.js] // firebaseAdminを読み込みます const admin = require('firebase-admin') const firebaseTools = require('firebase-tools') // Expressと関連プラグインも読み込む const express = require('express') const cors = require('cors') const bodyParser = require('body-parser') // Expressの拡張 const app = express() app.use(cors()) app.use(bodyParser.urlencoded({ extended: true })) app.use(bodyParser.json()) // このあたりの情報はFirebaseの管理画面から取得できる const adminKey = { 'type': 'service_account', 'project_id': 'xxxxx', 'private_key_id': 'osieteagenaiyo---da', 'private_key': '-----BEGIN PRIVATE KEY-----ながーいキーです\n-----END PRIVATE KEY-----\n', 'client_email': 'xxxx', 'client_id': 'xxxxx', 'auth_uri': 'xxxxxx', 'token_uri': 'xxxxxxx', 'auth_provider_x509_cert_url': 'xxxxxx', 'client_x509_cert_url': 'xxxxxx' } // Firebase Adminの初期化処理 admin.initializeApp({ credential: admin.credential.cert(adminKey), databaseURL: 'https://xxxxxx.firebaseio.com' }) // ここからサーバの処理 // 例えばこの処理は閉じられたグループの一覧を取得してフロントに返す処理 // Nipoは破棄されたグループにはdroped: trueというプロパティが追加される // firebase.のかわりに admin.を使う点以外はほとんど同じように使える app.post('/getClosedGroup', (req, res) => { console.log(req.body) // 削除済みのグループを取得 admin.firestore().collection('rooms').where('droped', '==', true).get().then(rooms => { const list = [] rooms.forEach(doc => { list.push(doc.id) }) res.json({ list: list }) }) }) // 例えばこれは指定されたグループIDを削除するプログラム // 削除するグループIDなどのパラメータはフロントから受けとり、req.body.変数名 に格納されます // なお、firebaseTools.firestore.delete を使うことでサブコレクションも含めて削除してくれます。 app.post('/deleteGroup', (req, res) => { console.log('削除するグループ', req.body.roomId) firebaseTools.firestore.delete(`test`, { project: 'xxxxxx', recursive: true, yes: true }).then(() => { res.json({ state: 1 }) }) }) // サーバーを起動する部分 console.log('Webサーバが起動しました。localhost:3000からアクセス可能です') app.listen(3000, function () {})
依存関係の解決は次の通りです
{ "name": "srv", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "exe": "nodemon ./src/index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "body-parser": "^1.19.0", "cors": "^2.8.5", "express": "^4.17.1", "firebase-admin": "^8.8.0", "firebase-tools": "^7.8.1" } }
Expressサーバを起動する
ExpressはNode.jsで動かします。なので、先ほどのindex.jsファイルがある場所へ移動して node index.jsを叩くだけです。
cd srv/src/ node index.js >Webサーバが起動しました。localhost:3000からアクセス可能です
ただ、この手順だとExpressのプログラムを修正しても自動で再起動してくれません。毎回CTRL+Cでサーバを落として、再起動しないと修正内容が反映されないのは開発効率を壊滅的に悪化させます。フロントの開発では自動リロードは当たり前なので、Expressも自動リロードをしてもらいましょう。
Expressを自動リロードありで起動する
Expressの変更を検知して再起動してくれる機能はいくつかありますが、私はnodemonを利用しています。nodemonをグローバルにインストールしましょう
npm install -g nodemon
あとは node index.jsの代わりに nodemon index.jsと叩くだけです。npmのスクリプトに登録しておいて、
"scripts": { "exe": "nodemon ./src/index.js", "test": "echo \"Error: no test specified\" && exit 1" },
npm run exe
のように起動することもできます。この辺りは好みですね。結果は同じです。
フロントの管理画面を作る
サーバに命令を与える管理画面があると操作がかんたんになります。また、自分以外にも操作させることもできるので、やっぱり管理画面はあった方がいいですね。フロント回りは軽くサーバに通信する部分だけ書いておきます。
ExpressへアクセスするためにAxiosを使いました。Vue.jsが推奨しているのでAxiosを使いますが他のツールでもいいです。
// これはVueで書かれているソースの一部です。 axiosは httpという自作関数でラップしちゃいました import * as http from 'components/http' export default { data () { return { list: [] } }, methods: { async getDeleteRoomList () { // サーバのURL /getClosedGroup にアクセスして、サーバから帰ってきたデータをresに格納します // これをView側に書いてあげると削除されたグループの一覧がみれます。v-forあたりが最適です const res = await http.post({ url: 'getClosedGroup' }) this.list = res.data.list }, async deleteRoom (roomId) { // サーバに対してパラメータを渡したい場合はこのように書く。この例だとroomIdという変数をExpressに渡せる const res = await http.post({ url: 'deleteGroup', data: { roomId: roomId } }) // 成功したとか失敗したとかこのあたりの処理は省略 } } }
axiosをラップしてしまっている関数の中身はこちらです
/** * httpsでCloud Functionsのnode.jsにアクセスする場合に使います。 */ import axios from 'axios' export async function post (p) { const param = { method: 'POST', url: `http://127.0.0.1:3000/${p.url}`, data: p.data } const res = await axios(param) return res }
結局やっていることは、フロントのVue.jsでExpressにアクセスし、Express上でFirebase Adminが動くというからくりです。
サーバ不要で直接Firebase Adminが操作できれば楽でいいんですけどね・・・・
コメント