LoginSignup
2
4

More than 3 years have passed since last update.

ユーザーに見えない処理はすべてCloud Functionsに任せよう

Last updated at Posted at 2020-01-31

TL;DR

Firebaseでのアプリ開発において、Viewに影響しない処理はCloud Functionsに投げてしまおうという話です。
Storageのお掃除や、Authenticationの設定など。

なぜCloud Functionsを使うのか?

本来、クライアントは画面や操作に影響する処理のみを扱うべきだと思います。

そうではない処理はサーバーに任せてしまった方が良き。

(ユーザー数の多いアプリケーションの場合、サーバーへの負荷分散のためあえてクライアント側に処理を任せることもあると思いますが。)

Cloud Functionsはデータベースやストレージに変更があった際など、イベントをトリガーに実行できるので「後でこれやっておいて〜」という処理を実装するのに便利です。

弊社ではザックリ以下のように分類しています。

  • すぐにレスポンスが欲しい → Swiftで実装
  • 後から処理してくれれば良い → Cloud Functionsで実装

UI/UXの観点からどちらで実装するか選べば良いかなと思います。

Cloud Functionsを使う準備

※Firebaseを使ったことがある方向けに端折って書いています。

  1. firebase initする際にFunctionsを選択、JavaScriptTypeScriptを選ぶ
  2. 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でよく実装する機能たち

いくつか例をあげていきます。

特定ユーザーに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)、カスタム権限を設定して管理者扱いにできます。

動画アップロード時にサムネイルを自動生成

この記事がめちゃくちゃ参考になりました。

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;
        });
    }
});

画像ファイルにキャッシュを設定して次回の表示を高速化できます。

サンプルコードは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エンジニアの人もある程度かけるようになるとハッピーですね。

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4