TL;DR
Firebaseでのアプリ開発において、Viewに影響しない処理はCloud Functionsに投げてしまおうという話です。
Storageのお掃除や、Authenticationの設定など。
なぜCloud Functionsを使うのか?
本来、クライアントは画面や操作に影響する処理のみを扱うべきだと思います。
そうではない処理はサーバーに任せてしまった方が良き。
(ユーザー数の多いアプリケーションの場合、サーバーへの負荷分散のためあえてクライアント側に処理を任せることもあると思いますが。)
Cloud Functionsはデータベースやストレージに変更があった際など、イベントをトリガーに実行できるので「後でこれやっておいて〜」という処理を実装するのに便利です。
弊社ではザックリ以下のように分類しています。
- すぐにレスポンスが欲しい → Swiftで実装
- 後から処理してくれれば良い → Cloud Functionsで実装
UI/UXの観点からどちらで実装するか選べば良いかなと思います。
Cloud Functionsを使う準備
※Firebaseを使ったことがある方向けに端折って書いています。
-
firebase init
する際にFunctions
を選択、JavaScript
かTypeScript
を選ぶ -
firebase init
完了後に作成されたfunctions
フォルダ内でnpm install -S firebase-functions firebase-admin
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp(); // 最近、optionsを指定する必要がなくなりましたね
Cloud Functionsでよく実装する機能たち
いくつか例をあげていきます。
特定ユーザーにAdmin権限の付与
exports.addAdminClaim = functions.database.ref('admin/{adminId}')
.onCreate((snap: any, context: any) => {
const uid = context.params.adminId;
modifyAdmin(uid, true);
});
const modifyAdmin = (uid: string, isAdmin: boolean) => {
admin.auth().setCustomUserClaims(uid, {admin: isAdmin}).then(() => {
console.log(`Successfully changed [${uid}]'s authentication.`)
}).catch((error) => {
console.error(`Failed to change [${uid}]'s authentication. `, error)
})
};
Firebase Authで作成したユーザーのUIDを、adminモデルに追加した時(onCreate)、カスタム権限を設定して管理者扱いにできます。
動画アップロード時にサムネイルを自動生成
この記事がめちゃくちゃ参考になりました。
Firebase Storage に動画ファイルがアップロードされたら Cloud Functions で自動的にサムネイルを作成する
画像アップロード時にキャッシュを設定
exports.setMetadata = functions.storage.object().onFinalize((object: any) => {
const filePath = object.name;
const { contentType } = object;
const fileRef = bucket.file(filePath);
const newMetadata = {
cacheControl: 'public,max-age=86400',
};
// ここでcontentTypeに応じてメタデータを変えてみたりとか
if (contentType.startsWith('image/')) {
fileRef.setMetadata(newMetadata).then(() => {
console.log('Set Metadata'); // eslint-disable-line
return true;
}).catch((err) => {
console.log(err); // eslint-disable-line
return false;
});
}
});
画像ファイルにキャッシュを設定して次回の表示を高速化できます。
サンプルコードは86400秒=24時間で設定してみました。
(要件に応じてチューニングしてください)
データ削除時にひもづく画像/動画/ファイルをCloud Storageから削除
exports.fileDelete = functions.database.ref('hoge/${id}')
.onDelete((snap: any, context: any) => {
// idと削除対象のファイル名を同一にしている場合
const id = context.params.id;
// fugaフォルダのidと同じ名前のjpegファイルを削除
return admin.storage().bucket().file(`/fuga/${id}.jpeg`).delete();
});
detabaseのデータ削除をトリガーに、データIDと同じファイルをCloud Storageから削除します。
クライアント側ではDBのデータ削除のみ書けばOKです。
Cloud Functionsのまとめ
「何かを削除した時に一緒にこれも消したい」とか「何かを作った時に、設定値を追加しておきたい」といった処理をさせるには便利だな〜という印象です。
デバイスにPush通知を送るときにCloud Functionsは必須なので、iOS/Androidエンジニアの人もある程度かけるようになるとハッピーですね。