Pei's Lab

Raspberry PiからFirebase Functionsをデプロイ

Google Homeのアプリケーションを開発する時に、DailogFlowを使用することがよくあります。簡単なやりとりであればDialogFlowだけで完結する場合もありますが、多くの場合話しかけられた文章に何かしらのバックエンドの処理を行うことになります。

今回はその準備として、Firebase Functionsを使える様に環境を整えていきます。Firebase Functionの場合、ローカルのNode.js環境にfirebaseのパッケージをインストールし、このパッケージを用いてローカルで作成したコードをクラウド上にデプロイ(コードをアップロードしてサーバーで使える様にすること)していきます。

開発環境作成

今回はNode.js環境が整っているRaspberry Piにfirebase関連のパッケージをインストールし、Raspberry Piへssh接続を行った状態からFirebase Functionのコーディング・デプロイを行ってみようと思います。Node.jsの環境が整っていない方はこちらの記事を参考にNode.js(特にnpm)が使える様にしておいてください。

Raspberry Piにnode.js/npm/google-home-notifierを導入

まず、Firebaseと通信するために”firebase-tools”をインストールします。

$ sudo npm install -g firebase-tools

オプションで-gを設定しているので、コマンドを実行するときのディレクトリに注意する必要はありません。勝手にいい感じのところにインストールしてくれます。

続いて、ローカルのNode.js環境とFirebaseアカウントを紐づけるためにログインします。

$ firebase login --no-localhost

今回はRaspberryPiにssh接続した状態で、Raspberry PiのNode.js環境とFirebaseを紐付けるので--no-localhostというオプションを設定します。使用している端末にNode.js環境が入っていて、その端末とFirebaseを紐づける場合には不要なオプションです。

あとは指示に従って進めていけばOKです。

#匿名のエラー情報収拾に協力するかを選択(y/n)
? Allow Firebase to collect anonymous CLI usage and error reporting information?  
 Yes

#紐づけるためのURLが生成される。"https://[長いURL]"にアクセスしてグーグルアカウントでの認証を行う
Visit this URL on any device to log in:
https://[長いURL]

#アカウント認証が成功すると認証コードが生成されるので、入力する。
? Paste authorization code here: [認証コード]

 Success! Logged in as account@gmail.com

--no-localhostの設定が適切でないと、認証コードの生成時にエラーが出ます。私はここでしばらくハマりました。ご注意ください。

次に、コーディング・デプロイ用のディレクトリを作っていきます。ディレクトリは任意の場所で構いません。私の場合は

$ pwd
/home/pi/Development/Firebase/fb_functions

こんな感じにしてみました。これがいい感じなのかどうかも今はよくわからないので、問題などが見つかったら記事修正します。

作成したディレクトリに移動して、以下を実行していきます。

#作成したディレクトリをFirebase Function用に初期化する。
$ firebase init functions

     ######## #### ########  ######## ########     ###     ######  ########
     ##        ##  ##     ## ##       ##     ##  ##   ##  ##       ##
     ######    ##  ########  ######   ########  #########  ######  ######
     ##        ##  ##    ##  ##       ##     ## ##     ##       ## ##
     ##       #### ##     ## ######## ########  ##     ##  ######  ########

You're about to initialize a Firebase project in this directory:

  /home/pi/Development/Firebase/fb_functions


=== Project Setup

First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add, 
but for now we'll just set up a default project.
#(訳)
#最初にこのディレクトリとFirebaseのプロジェクトを紐づけます。
#"firebase use --add"コマンドを実行することで、プロジェクトに別名をつけることも可能です。
#今回は単にデフォルトプロジェクトを設定します。

#どのプロジェクトと紐づけるかを聞かれる。
#Firebaseですでにプロジェクトを作ってあればそれを選択しても良いし、新しく作成することも可能。
? Select a default Firebase project for this directory: porject-id(project-name)
i  Using project porject-id(project-name)

=== Functions Setup

A functions directory will be created in your project with a Node.js
package pre-configured. Functions can be deployed with firebase deploy.

#使用する言語を聞かれる。JavaScriptかTypeScriptを選択する。今回はJavaScript
? What language would you like to use to write Cloud Functions? JavaScript

#JavaScriptの構文チェック機能(ESLint)を有効にするか聞かれる。どちらでもOK
? Do you want to use ESLint to catch probable bugs and enforce style? Yes
 Wrote functions/package.json
 Wrote functions/.eslintrc.json
 Wrote functions/index.js
 Wrote functions/.gitignore

#依存関係にあるパッケージをいまnpmでインストールしてよいか聞かれる。Yesのほうが良いと思われる。
? Do you want to install dependencies with npm now? Yes

> protobufjs@6.8.8 postinstall /home/pi/Development/Firebase/fb_functions/functions/node_modules/protobufjs
> node scripts/postinstall

npm notice created a lockfile as package-lock.json. You should commit this file.
added 348 packages from 250 contributors and audited 881 packages in 54.868s
found 0 vulnerabilities


i  Writing configuration info to firebase.json...
i  Writing project information to .firebaserc...
i  Writing gitignore file to .gitignore...

 Firebase initialization complete!
#初期化完了しました!

初期化できたところで、ディレクトリの構成を確認してみましょう

$ tree -L 2
.
├── firebase.json
└── functions
    ├── index.js
    ├── node_modules
    ├── package-lock.json
    └── package.json

treeはディレクトリの構造を表示するコマンドで、オプション-Lは何層したの階層まで表示するかを決めるオプションです。このオプションを設定しない場合は配下の全てのファイルが表示されることになり膨大な長さのツリーが表示されてしまいます。Lはlayerの頭文字ですかね?

functionsというディレクトリが追加され、その中にindex.jsが作られているのが確認できます。Firebase Functionsのコードはこのindex.jsに書いていきます。

Hello Worldのデプロイ

先ほど述べたindex.jsの中を覗くと、コメントアウトこそされているものの、すでにHello Worldのコードが記載されています。コメントアウトを解除すば、Hello Worldのコードが出来上がりです!

index.js

const functions = require('firebase-functions');

// Create and Deploy Your First Cloud Functions
//(訳)最初のクラウドファンクションを作ってデプロイしてみましょう
// https://firebase.google.com/docs/functions/write-firebase-functions
exports.helloWorld = functions.https.onRequest((request, response) => {
 response.send("Hello from Firebase!");
});

コードができたらあとはデプロイです。デプロイは先ほどtreeコマンドを実行したときと同じディレクトリで行います。

$ firebase deploy

=== Deploying to 'プロジェクト名'...

i  deploying functions
Running command: npm --prefix "$RESOURCE_DIR" run lint

> functions@ lint /home/pi/Development/Firebase/fb_functions/functions
> eslint .

   functions: Finished running predeploy script.
i  functions: ensuring necessary APIs are enabled...
   functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (37.16 KB) for uploading
   functions: functions folder uploaded successfully
i  functions: creating Node.js 8 function helloWorld(us-central1)...
   functions[helloWorld(us-central1)]: Successful create operation. 
Function URL (helloWorld): https://us-central1-project-name.cloudfunctions.net/helloWorld

   Deploy complete!

Project Console: https://console.firebase.google.com/project/project-name/overview

うまくデプロイできればこんな感じになります。Function URLに記載のURLにアクセスすると、「Hello from Firebase!」と表示されるのが確認できます。

まとめ

以上でFirebase Functionsを使うための環境設定と、コーディング、デプロイの流れを確認できました。あとはindex.jsのコードを機能に合わせて編集すればOKです!