FirebaseとSendGridを上手く利用するには?

FirebaseとSendGridを上手く利用するには?

記事
IT・テクノロジー

FirebaseとSendGridを上手く利用するには?

FirebaseとSendGridを使ってメルマガ(ニュースレター)サービスを実装する場合、SendGridのサーバーからデータを取得する場合の処理は:
* バックエンドにリクエストを送信
* バックエンドはリクエストをSendGridに転送
* バックエンドがSendGridからデータを受け取る
* バックエンドがデータをフロントエンドに転送
というステップで処理が実行されます。
SendGridとのやり取りにAPI Key(SendGridの秘密鍵)を利用する必要があるのでどうしても、バックエンドと通す必要があるため、意外に時間がかかります。
今日の記事は、FirebaseとSendGridでメルマガ(ニュースレター)のサービスを実装する際に、こうした待ち時間を改善する方法について解説します。

Firebaseのデータベースアクセスは高速アクセス可能!

バックエンドのサービス(functions)とそのホスティングにFirebaseを使う場合、もう一つ工夫するとメルマガ(ニュースレター)を配信する際のサービスをより快適にすることができます。
Firebaseのデータベース(Cloud Firestore)は、チャットなどのサービスでもよく利用されますが、リアルタイムでの更新も可能で、高速でアクセス可能です。これを上手く使うとSendGridのデータの取得も高速かつ便利に行う事が可能です。
少なくても、Firebase Cloud Firestoreのデータベースにはバックエンドを介さずに直接アクセスすることもできるので、SendGridのよく利用するデータをFirebase Cloud Firestore上にコビーを作っておけば非常に高速でデータを取得する事が可能になります。
要するに、SendGridにあるデータの一部をFirebaseのデータベース(Cloud Firestore)上にキャッシュしてアクセスの効率を上げるという方法です。

基本的なコンセプト

この方法の基本コンセプトの詳細を順番に説明していきます。
フロントエンドのサービスにアクセスしたら最初に必要なデータを取り込む。 メルマガ(ニュースレター)のサービスにアクセスした際に最初によく使うデータを取り込んでしまいます。
取り込む際は「onSnapshot」を使って取り込みます。
例えば、メッセージの送付先を「recipients」というコレクションに保存している場合は、以下のようなコードで取り込むことができます。
let recipients:Array<TYPE.Recipient> = [];
firebase.
    firestore().
    collection("recipients").
    onSnapshot().
    then((querySnapshot:firebase.firestore.QuerySnapshot) => {
        for (let i = 0 ; i < querySnapshot.size ; i++) {
            recipients.push(querySnapshot.docs[i].data())
        }
    })
この方法のメリットは、Firebaseのこのコレクションのデータが更新されると自動的に取り込んでいるデータの更新を行える点です。つまり、自分自身で送付先のデータを追加した場合は勿論ですが、別な人がデータを追加した場合にも特に何もしなくても取り込んでいるデータが更新されます。

Firebase Cloud Firestoreの管理

この方法を利用する場合に一番重要なことは、SendGridのデータとFirebaseのCloud Firestoreのデータが同じであるという事です。従って、SendGridのサーバー上のデータを操作した場合は、Firebase Cloud Firestore上のデータも更新する必要があります。
SendGrid上のデータが変更される処理は基本的に
* データの新規追加(送付先の新規登録)
* データの更新(既存の送付先の情報の更新)
* データの削除(登録されている送付先の削除)
です。この操作を行った場合、Firebase Cloud Firebaseのデータも更新するようにします。
新規追加と更新の場合
新規追加と更新の場合はシンプルです。まずは、SendGridのサーバーのデータをAPIを使って更新します。 実際は、フロントエンドからの処理を転送すれば、SendGrid上のデータは更新されます。 その処理が終了した後に、全てのデータを一括でSendGridにリクエストして、その応答データをFirebase Cloud Firestoreに入れればよいことになります。
addRecipient(recipient:TYPE.Recipient).then(() => {
     const ref:firebase.firestore.collectionReference =
        firebase.
        firestore().
        collection("recipients");
        getRecipients().then((recipients:Array<TYPE.Recipients>) => {
            for (let i = 0 ; i < recipients.length ; i++>) {
                ref.
                    where("id", "==", recipients[i].id).
                    get().
                    then((querySnapshot:firebase.firestore.QuerySnapshot) => {
                        if (querySnapshot.size === 0) {
                            // Firebase Cloud Firestoreにドキュメントが存在しない場合
                            // ドキュメントを新規追加
                            ref.add(recipients[i]).catch((error:any) => {
                            });
                        } else if (querySnapshot.size === 1) {
                            // Firebase Cloud Firestoreにドキュメントが存在する場合
                            // ドキュメントのデータを更新
                            const docId = querySnapshot.docs[0].id;
                            ref.doc(docId).set(recipients[i]).catch((error:any) => {
                            })
                        } else {
                            // Firebase Cloud Firestoreに複数のドキュメントが存在する場合
                            // (エラー)
                        }
                    }).catch((error:any) => {
                        // Firebase Cloud Firestoreからのデータの取得に失敗
                        // (エラー)
                    })
            }
        }).catch((error:any) => {
            // SendGrid からの登録先の一覧取得に失敗
            // (エラー)
        })
    }).catch((error:any) => {
        // SendGridの送付先の登録に失敗
        // (エラー)
    })
バックエンドで送信先の登録を行った場合、登録後にSendGridから登録されている送付先を取得して、その情報を既存のFirebase Cloud Firestoreの情報に上書きする処理をすれば、Firebaseの情報は更新されます。 フロントエンドが「onSnapshot」でデータを取得している場合はこの更新のイベントがフロントエンドに送られて自動更新されます。
削除の場合
削除の場合、新規追加や更新の様にデータを取得する方法では上手く行きません。 Firebase上に削除したデータが残っているためです。
削除の場合、SendGrid上の削除の処理が成功した場合、該当するデータをFirebase Cloud Firestore上から削除する処理が必要です。
deleteRecipient(id:number).then(() => {
    const ref:firebase.firestore.CollectionReference = firebase.
        firestore().
        collection("recipients")
    ref.where("id","==", id).get().then((querySnapshot:firebase.firestore.QuerySnapshot) => {
        if (querySnapshot.size === 1) {
            const docId = querySnapshot.docs[0].id;
            ref.doc(docId).delete().catch((error:any) => {
                // 削除失敗 (エラー)
            })
        } else {
            // 複数のドキュメントもしくはドキュメントが存在しない(エラー)
        }
    })
})
この場合も、フロントエンドで「onSnapshot」でデータを取得している場合自動更新されます。

Firebase Cloud Firestoreからデータを取得

このように、Firebase Cloud FirestoreにSendGrid上のデータのコピーを置いておけば、フロントエンドは必要な場合は、Firebase Cloud Firestoreからデータを取得するようにすれば、SendGridからバックエンドを介してデータを取得するより高速でデータを受け取ることが可能になります。
この方法では、バックエンドがSendGrid上のデータを更新してからFirebase Cloud Firestoreのデータを更新するまでに短い時間ですがデータが一致しない時間があります。 しかし、このメルマガ(ニュースレター)のサービスを考えた場合、古いデータを利用した場合の問題はほとんどない場合が多くなります。SendGridから直接データを取得していたとしても、複数の利用者がSendGridのデータを更新できる場合は、同じような状況は発生します。
従って、Firebaseのデータベースを利用するデメリットは殆どないという事になります。
このような実装をすると、SendGridのデータを操作する場合はSendGridまでリクエストを送る必要がありますが、それ以外のデータを取得するだけの場合はFirebaseからデータを受け取るだけで済むので、利用者の待ち時間を少なくすることが可能になります。

まとめ

FirebaseとSendGridを使ってメルマガ(ニュースレター)のサービスを実装する場合、Firebase Cloud FirestoreにSendGridのデータのコピーを作っておくと、利用者の待ち時間を改善する事ができます。 単にバックエンドをリクエストの仲介役にするだけではなく、Firebaseの他の機能を上手く組み合わせてサービスに組み込むことでよりよいサービスを実現できる場合がたくさんあります。
Firebaseは多くの機能をサポートする強力な仕組みです。WebサービスやWebアプリを実装する際は、そうした機能が利用できないかを考えると、サービスの機能の改善が可能になる場合がたくさんあります。既に稼働しているサービスでも工夫できる点がある場合があります。
今一度、Firebaseのサポートする機能を見てみると良いと思います!
サービス数40万件のスキルマーケット、あなたにぴったりのサービスを探す ココナラコンテンツマーケット ノウハウ記事・テンプレート・デザイン素材はこちら