Cloud functions for Firebaseとは
Cloud functions for FirebaseはFirebaseの機能やHTTPS要求によってトリガされたイベントに応答して、自動的に用意したバックエンドコードを実行することができます。これらのバックエンドコードはGoogleのクラウドに保存され管理&自動実行されるので、自分でサーバー管理及び拡張する必要はありません。
現在サポートしているFirebaseの機能
- Realtime Database Triggers
- Writes to Realtime Database
- Firebase Authentication Triggers
- New user authentication
- Google Analytics for Firebase Triggers
- Analytics conversion events
- Cloud Storage Triggers
- Uploads to your storage bucket
- HTTP Triggers
- Incoming HTTPS requests
- Cloud Pub/Sub Triggers
サポートしている言語
現在はnode.jsのみサポート、今後他の言語もサポートする予定
環境構築
- nodeのインストール
brew install node
- Firebase CLIのインストール
sudo npm install -g firebase-tools
- 任意のフォルダを作成
mkdir functions-firebase
cd functions-firebase
- firebase にログイン
firebase login
- プロジェクトの初期化
firebase init
- Functions: Configure and deploy Cloud Functionsを選択
- GCPプロジェクトの選択
- Do you want to install dependencies with npm now? Yesを選択
デプロイ
index.jsを開いてください。そこにHTTPリクエストのイベントに応答するサンプルコードがコメントアウトされています。そのコメントアウトを解除し、function名を"sayHelloWorld"にしてください。
const functions = require('firebase-functions');
// Create and Deploy Your First Cloud Functions
// https://firebase.google.com/docs/functions/write-firebase-functions
exports.sayHelloWorld = functions.https.onRequest((request, response) => {
response.send("Hello from Firebase!");
});
firebase deploy
デプロイが終わるとfunction URLが返ってくるので、ブラウザでアクセスしてください。
Function URL (sayHelloWorld): https://us-central1.../satHelloWorld
ブラウザに"Hello from Firebase!"が表示されればデプロイ成功です。
Firebaseコンソールにログを出してみる
const functions = require('firebase-functions');
// Create and Deploy Your First Cloud Functions
// https://firebase.google.com/docs/functions/write-firebase-functions
exports.sayHelloWorld = functions.https.onRequest((request, response) => {
console.log("Hello from Firebase!");
response.send("Hello from Firebase!");
});
firebase deploy
またブラウザでFunction URLにアクセスしたらFirebaseコンソールのログを見てみます。
Firebaseコンソール > functions > ログ
"Hello from Firebase!" が表示されれば成功です。
Authentication Trigger
Authentication Triggerではユーザーが作成されたときや削除された時のイベントを取ることができます。こちらのTriggerを利用すればユーザーが会員登録をした際に自動返信メールを出すことができます。
ユーザーが作成された時
新しいユーザーが作成されたらデータベースにUserデータを作成し、デフォルトのユーザーアイコンの画像URLを挿入する。
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase)
const ref = admin.database().ref()
//Authentication Trigger
exports.createUserAccount = functions.auth.user().onCreate(event => {
const uid = event.data.uid
const email = event.data.email
const photoUrl = event.data.photoUrl ||
'photo_url'
const newUserRef = ref.child(`/users/${uid}`)
return newUserRef.set({
photoUrl: photoUrl,
email: email
})
})
ユーザーが削除された時
ユーザーが削除されたら削除済みフラグ("isDeleted: true")をユーザーデータに自動的にセットさせる
exports.cleanupUserData = functions.auth.user().onDelete(event => {
const uid = event.data.uid
const userRef = ref.child(`/users/${uid}`)
return userRef.update({isDeleted: true})
})
Realtime Database Trigger
Realtime Database Triggerではデータベースの書き込みなどのイベントを取得することが出来ます。
regionをJapanに書き換えするサンプル
//Realtime Database Trigger
exports.changePost = functions.database
.ref('/posts/{pushId}')
.onWrite(event => {
const post = event.data.val()
if (post.chnaged) {
return
}
post.chnaged = true
post.region = "Japan"
return event.data.ref.set(post)
})
fibreaseコンソールで/posts/{pushId}のregionに適当な値をいれて、データベース見ましょう。自動的にJapanに置き換わります。
Cloud Storage Trigger
CloudStorageにファイルが追加された時のイベントを取得することができます。下記のサンプルコードは"/image/"ディレクトリに画像が追加された時、自動的にサムネイル画像を生成します。
下準備
package.jsonがあるディレクトリで以下のコマンドを実行し必要なライブラリを導入します。
npm install --save @google_cloud/storage
npm install --save child-process-promise
package.jsonにこれらが入っていれば成功です。
"dependencies": {
"@google-cloud/storage": "^1.2.0",
"child-process-promise": "^2.2.1"
}
画像が追加されたら自動的にサムネイルを生成するコード
const functions = require('firebase-functions')
const gcs = require('@google-cloud/storage')();
const spawn = require('child-process-promise').spawn
//Cloud Storage Trigger
exports.generateThumbnail = functions.storage.object()
.onChange(event => {
const object = event.data
const filePath = object.name
const fileName = filePath.split('/').pop()
const fileBucket = object.bucket
const bucket = gcs.bucket(fileBucket)
const tempFilePath = `/tmp/${fileName}`
if (fileName.startsWith('thumb_')){
console.log('Already a Thumbnail.')
return
}
if(!object.contentType.startsWith('image/')){
console.log('This is not an image.')
}
if(object.resourceState === 'not_exists'){
console.log('This is a deletion event.')
}
return bucket.file(filePath).download({
destination: tempFilePath
}).then(() => {
console.log('Image downloaded locally to', tempFilePath)
return spawn('convert', [tempFilePath, '-thumbnail', '200x200>',
tempFilePath])
}).then(() => {
console.log('Thumbnail created')
const thumbFilePath = filePath.replace(/(\/)?([^\/]*)$/,
'$1thumb_$2')
return bucket.upload(tempFilePath, {
destination: thumbFilePath
})
})
})
さらに応用
サムネイル画像が追加されたらRealtime Databaseに画像のURLを追加します。
下準備
Firebaseコンソールの歯車アイコン>プロジェクトの設定>サービスアカウント>新しい秘密鍵の生成をクリックしjsonファイルを落としindex.jsと同じディレクトリにいれます。
画像のURLをRealtime Databaseに保存するサンプルコード
const functions = require('firebase-functions')
const gcs = require('@google-cloud/storage')({keyFilename:
'Firebaseコンソールでダウンロードしたjsonファイル.json'})
const spawn = require('child-process-promise').spawn
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)
//Cloud Storage Trigger
exports.generateThumbnail = functions.storage.object()
.onChange(event => {
const object = event.data
const filePath = object.name
const fileName = filePath.split('/').pop()
const fileBucket = object.bucket
const bucket = gcs.bucket(fileBucket)
const tempFilePath = `/tmp/${fileName}`
const ref = admin.database().ref()
const file = bucket.file(filePath)
const thumbFilePath = filePath.replace(/(\/)?([^\/]*)$/,
'$1thumb_$2')
if (fileName.startsWith('thumb_')){
console.log('Already a Thumbnail.')
return
}
if(!object.contentType.startsWith('image/')){
console.log('This is not an image.')
}
if(object.resourceState === 'not_exists'){
console.log('This is a deletion event.')
}
return bucket.file(filePath).download({
destination: tempFilePath
}).then(() => {
console.log('Image downloaded locally to', tempFilePath)
return spawn('convert', [tempFilePath, '-thumbnail', '200x200>',
tempFilePath])
}).then(() => {
console.log('Thumbnail created')
return bucket.upload(tempFilePath, {
destination: thumbFilePath
})
}).then(() => {
const config = {
action: 'read',
expires: '03-09-2491'
}
const thumbFile = bucket.file(thumbFilePath)
return Promise.all([
thumbFile.getSignedUrl(config),
file.getSignedUrl(config)
])
}).then(results => {
const thumbResult = results[0]
const originalResult = results[1]
const thumbFileUrl = thumbResult[0]
const fileUrl = originalResult[0]
return ref.child('posts').push({path: fileUrl, thumbnail: thumbFileUrl})
})
})