FirebaseでNode.jsを動かしてLINE BOTを作る


LINE BOTのホスティング先で色々試してましたが、Firebaseでも動的なアプリケーションを動かすことが出来るようになってたので試してみました。

静的サイトだけかと思ってたら、すごいですね。（ウォッチしてなかっただけ）

## 準備

* Node.js v11.9.0 (サーバー上は[v8系が最新っぽい](https://firebase.google.com/docs/functions/manage-functions?hl=ja#set_runtime_options))
* npm v6.8.0
* firebase-tools v6.5.0 
* 先に[Firebase](https://firebase.google.com/?hl=ja)でプロジェクトを作っておく

> 今回は先にプロジェクトがあったところからスタートしたのでこの手順紹介にします。

## Firebase CLIをインストールする

```bash
npm i -g firebase-tools
```

## CLIでログインする

```bash
firebase login
```

```
? Allow Firebase to collect anonymous CLI usage and err
or reporting information? [Y/n]
```

的な質問がくるので`Y`と答える

ブラウザが開かれるので、ログインするアカウントを選択して進めます。

<img src="https://i.gyazo.com/98ea6ae9e56ca7506eaa8fe61cf010c2.png" width="400px">

```
・
・
・
✔  Success! Logged in as xxxx@gmail.com
```

みたいな表示が出たらログイン成功です。

## ローカルでプロジェクト作成

```
firebase init functions
```

なんかかっこいい表示出ます。

<img src="https://i.gyazo.com/199890f8544404d15d019abfe416af1d.png" width="400px">

どのプロジェクトでスタートするかの選択肢が出てきます。`forlinebot`という名前でfirebaseのプロジェクトを作ったので真ん中の`forlinebot`という名前の箇所を選択します。

<img src="https://i.gyazo.com/fcc9f569b9cca169aef533f3b574d676.png" width="400px">

**このあとは基本的にEnterで進めて大丈夫だと思います。**

* JSかTSか

今回はJavaScriptでいきます。

<img src="https://i.gyazo.com/0c5909a0ea12ba0a083161aa73290e44.png" width="400px">

* ESLint使うか

そのままEnterで進めたのでNかな？

<img src="https://i.gyazo.com/0423eed1022ff5e3f45f801efa56cb19.png" width="400px">

* 依存モジュールをnpmで今入れるか

そのままEnterで進めたのでYes

> ? Do you want to install dependencies with npm now? Yes

そうするとこんな感じのフォルダとファイルが出来上がります。

<img src="https://i.gyazo.com/370e25a8736535a7c13b7c78867fda8a.png" width="400px">

`functionsフォルダ`、`.firebaserc`、`.gitignore`、`firebase.json`が生成され、functionsフォルダ内にアプリケーションのテンプレートが出来上がります。

## ExpressとLINE BOT SDKでBOT作成準備

依存モジュールのインストールをします。`functions`フォルダに移動してインストールします。

```bash
cd functions
npm i --save @line/bot-sdk express
```

`index.js`を以下の内容に書き換えます。 [こちらの記事](https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d)を参考に **`channelSecret`と`channelAccessToken`に値を入れましょう。**

```index.js
'use strict';

const functions = require('firebase-functions');
const express = require('express');
const line = require('@line/bot-sdk');

const config = {
    channelSecret: '',
    channelAccessToken: ''
};

const app = express();

app.post('/webhook', line.middleware(config), (req, res) => {
    console.log(req.body.events);
    Promise
      .all(req.body.events.map(handleEvent))
      .then((result) => res.json(result));
});

const client = new line.Client(config);

async function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  return client.replyMessage(event.replyToken, {
    type: 'text',
    text: event.message.text //実際に返信の言葉を入れる箇所
  });
}

exports.app = functions.https.onRequest(app);
```

`firebase.json`を以下に書き換えます。

```firebase.json
{
    "hosting": {
        "public": "./",
        "rewrites": [{
            "source": "/webhook",
            "function": "app"
        }],
        "ignore": [
            "firebase.json",
            "**/.*",
            "**/node_modules/**"
        ]
    }
}  
```

## アプリケーションの起動とngrokで動作確認

以下でlocalサーバーを起動します。

```bash
firebase serve --only functions,hosting
```

そうすると`localhost:5000`でサーバーが起動します。

> サーバー側だけなので、`functions`の指定だけで良いかと思いきやexpressのこのやり方だと`hosting`も指定しないとエラーが出ました。あんまり追ってないです。


[こちらの記事](https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d)を参考にngrokで5000番ポートへのトンネリングサーバーも起動しましょう。

```bash
ngrok http 5000
```

<img src="https://i.gyazo.com/833b7a4eadfce9e685831472acc5a35a.png" width="400px">

発行されたngrokのURLをLINE Developersのチャンネル設定でWebhook URLに設定します。

<img src="https://i.gyazo.com/916f21537a810e87c10d38643e0aff68.png" width="400px">

ここまでで問題がなければ、おうむ返しBOTが出来てると思います。

<img src="https://i.gyazo.com/88df631f6cd3d05fb1bc406a6c5916d6.png" width="400px">

## デプロイする

async/awaitを利用したいのでサーバー上のNode.jsのバージョンを最新([現時点で8系らしい](https://firebase.google.com/docs/functions/manage-functions?hl=ja#set_runtime_options))にします。

`functions/package.json`に以下のenginesの指定を追加します。

```
"engines": {"node": "8"}
```


さっきのコマンドのserveの部分をdeployに変えて実行します。

```bash
firebase deploy --only functions,hosting
```

```
=== Deploying to 'forlinebot-xxxx'...

i  deploying functions, hosting
i  functions: ensuring necessary APIs are enabled...
✔  functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (27.22 KB) for uploading
✔  functions: functions folder uploaded successfully
・
・
・
・

✔  Deploy complete!

Please note that it can take up to 30 seconds for your updated functions to propagate.
Project Console: https://console.firebase.google.com/project/forlinebot-xxxx/overview
Hosting URL: https://forlinebot-xxxx.firebaseapp.com
```

初回は少し時間がかかった印象ですが、2回目以降は結構はやくデプロイできました。

ここで生成されたアドレス( https://xxxx.firebaseapp.com )をLINE DevelopersのWebhook URLに設定しなおせば完了です。

<img src="https://i.gyazo.com/9ba93a2b4a138878e5850cad00028087.png" width="400px">

## 雑感

Firebase全くウォッチしてなかったけど便利やん。

## 参考

* [Firebaseで動かすNode.jsアプリ入門🔥](https://qiita.com/seya/items/225f859d775b31047000)
* https://www.youtube.com/watch?v=LOeioOKUKI8
* [1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest](https://qiita.com/n0bisuke/items/ceaa09ef8898bee8369d#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90%E3%81%A8%E3%83%8F%E3%83%AD%E3%83%BC%E3%83%AF%E3%83%BC%E3%83%AB%E3%83%89)