みなさん、Cloud Functionsをうまく活用していますか?
この記事は、Firebaseでのアプリ開発においてViewに影響しない処理はCloud Functionsに投げてしまおうという話です。
例えば以下のような処理は、すべてCloud Functionに任せることができます。
- Cloud Storageに保存したデータのメタデータ設定
- Authenticationの設定
- 定期的なデータ削除
ということでこんにちは、株式会社Playground Webシステム開発部の稲垣です!
Firebaseはバックエンドの大部分を肩代わりしてくれるサービスですよね。
そして、Cloud Functionsをうまく使うと、SwiftやJava(Kotlin)のコード量を減らして、クライアントの負担を軽くすることができます。
目次
なぜ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`
functions/src/index.ts
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp(); // 最近、optionsを指定する必要がなくなりましたね
Cloud Functionsでよく実装する機能たち
Playgroundで開発する中で実装してきたCloud Functionsたちをいくつか例としてあげていきます。
特定ユーザーにAdmin権限の付与
functions/src/index.ts
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)、カスタム権限を設定して管理者扱いにできます。
動画アップロード時にサムネイルを自動生成
動画を扱うアプリケーションであれば、サムネイルを設定したいという要件はきっとありますよね。
これもCloud Functionsにお任せすることができます。
コードを載せるととても長くなるので、参考にした記事リンクを貼っておきます。
Firebase Storage に動画ファイルがアップロードされたら Cloud Functions で自動的にサムネイルを作成する
画像アップロード時にキャッシュを設定
functions/src/index.ts
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;
});
}
});
画像ファイルにキャッシュを設定して次回の表示を高速化できます。
Cloud Storageのデフォルトは3600秒ですが、サンプルコードでは86400秒=24時間に設定してみました。
(要件に応じてチューニングしてください)
データ削除時にひもづく画像/動画/ファイルをCloud Storageから削除
functions/src/index.ts
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エンジニアの人もある程度かけるようになるとハッピーですね。
- 無料・簡単・片手でホームページを作成できる自社サービス Rakwi
- Web制作とアプリ開発を学べるオンラインプログラミング講座 Upstairs
- 開発,DX推進支援サービス スタートアッププラン