ローカル環境で LINEWORKS Bot を動かす話

LINEWORKS Advent Calendar 2019 の 3日目を担当させていただきます！
どうぞよろしくおねがいしますm(_　_)m

さっそくですが、タイトルの通りローカル環境で LINEWORKS Bot を動かす話をしたいと思います。

開発用に自由に使えるサーバを持ってない私にとって、LINEWORKS Bot を実際に動かすのに GoogleAppsScripts が便利なのでよく使っています。
ですが、Node.js が基本スキルの私にとって、GAS は Javascript に近い作りですが微妙に違ってくるので、やっぱりちゃんと Node.js のコードでテストしたい！って思うわけなのです。

ローカル環境でトーク Bot を動かすには、
1. ローカル環境に http サーバを立ててアプリケーションを動かして
2. 外部公開用の URL を取得して Bot の Callback URL に登録する

と、いう流れになりますねー。
では、さっそくやっていきますね。

## ローカル環境に http サーバを立ててアプリケーションを動かす

たぶん、読んでる方々には釈迦に説法状態だと思うので、非常に恐縮なのですが。。。
Node.js には `express` という、すんばらごいモジュールがいらっしゃいます。(ﾟДﾟ)ﾉ
知っている方は読み飛ばしていただいて結構ですよ！( ;∀;)

では、`express` をさくっとインストールしていきましょー。

と、その前に `package.json` ファイルを作ります。
このアプリケーションはこんなアプリケーションですよーってファイルです。
「わかってるよ！もうあるよ！」って方はごめんなさい。読み飛ばしてください。

以下のコマンドを実行してください。

```
> npm init
```

英語で質問されるので、ペラペラバイリンガルなあなたは適切に答えていただければ大丈夫！
英語得意じゃないので全部 `Enter`！(ﾟДﾟ) それでも大丈夫！

`package.json` ファイルが作成されますので、中身を開いてみてください。

真ん中らへんに `"start"` の項目があると思うので以下のように書き換えます。

```
"scripts": {
  "start": "node ./app.js"
},
```

設定が終わったら `express` をインストールします。

```
> npm install express --save
```

インストールが終わったら、アプリケーションのコードを書いていきましょう！
単純に、メッセージを受け取ってコンソールに表示するだけのプログラムです。

```app.js
const express = require('express');
const app = express();
const port = xxxx; // port には任意の値を入れてください。
app.listen(port);

app.post('/callback', function(req, res) {
    console.log(req.body);
});
```

`npm start` で実行してアプリケーションを起動させます！

```
> npm start
```

これで準備は OK です！
次の手順に進みましょう。

## 外部公開用の URL を取得して Bot の Callback URL に登録する

ローカル環境を外部公開するなんて、どうしたらいいのやらやら。
そんなとき大活躍してくれる強い味方！ [ngrok](https://ngrok.com/) さんです！ヾ(*´∀｀*)ﾉ

・・・なんか、モジュール紹介になってる気もしますが、これ、全部 LINEWORKS Bot を使うためですから！(^_-)-☆

`ngrok` さんを使えば、ローカル環境のサーバを外部公開できます！
LINEWROKS Bot の Callback URL は `https` でないといけないのですが、もちろん `ngrok` さんは `https` の URL を作成してくれんですよ～。ありがたい(*´Д｀)

それでは、さくさくっといきましょー。
まずは、別のターミナルを起動して `ngrok` さんをインストールしてください。

```
> npm install ngrok --save
```

そして、あとはコードを書いて実行するだけ。

```getCallbackUrl.js

const ngrok = require('ngrok');
const port = xxxx; // port には任意の値を入れてください。
ngrok.connect(port).then((ngrokUrl) => {
    console.log('bot callback URL : ' + ngrokUrl + "/callback");
});
```

すると、ローカル環境がサーバとなり、URL が発行されます。

```
> node .\getCallbackUrl.js
bot callback URL : https://ff7b9d27.ngrok.io/callback
```

あとはこの URL を Bot に登録すれば OK！
こんなに楽チンに `https` の URL が取得できちゃうなんて、ありがたいですよねー(*´Д｀)

## API で Callback URL を登録する

ngrok での URL はプログラムを終了すると取得しなおしになるので、その度に Bot に登録し直しになります。
次の日とか、URL 取り直してー、登録し直してー、ってやらないといけません。
めんどいっ！(ﾟДﾟ)ﾉ

URL を取得したらそのまま登録しちゃえばいいんですよ！
ってなわけで、さっきのコードを改造していきます。

Callback URL を登録するのに API を使うので `request-promise` モジュールを先にインストールしておきます。

```
> npm install request-promise --save
```

普通の `request` モジュールでもいいのですが、`request-promise` だとエラー処理が `.catch` でできるので愛用しています。
インストールしたら準備は OK！
コードを書いていきましょう。

```setCallbackUrl.js

const ngrok = require('ngrok');
const port = xxxx; // port には任意の値を入れてください。
const request = require('request-promise');

ngrok.connect(port).then((ngrokUrl) => {
    console.log('bot callback URL : ' + ngrokUrl + "/callback");
    const options = { // apiId,consumerKey,token,botNo はご自身のものを入力してください。
        uri: "https://apis.worksmobile.com/" + apiId + "/message/setCallback/v2",
        headers: {
            "Content-type": "application/json",
            "consumerKey": consumerKey,
            "Authorization": "Bearer " + token
        },
        json: { 
            "botNo": botNo,
            "callbackUrl": ngrokUrl + "/callback",
            "callbackEventList": ["text", "sticker"]
        }
    };
    request.post(options).then((body) =>  { console.log(body) })
        .catch((error) => { throw new Error(error) });  
});
```

では、実行して Callback URL を登録しましょう！(=ﾟωﾟ)ﾉ

```
> node setCallbackUrl.js
bot callback URL : https://252b7e9b.ngrok.io/callback
{ message: 'OK', code: 200 }
```

200 OK をもらいましたが、念のため DeveloperConsole でも確認しましょう。
![1574750764.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/dc58a161-40f4-c893-cb37-65a6489e7d0f.png)

ちゃんと、登録されていますね！
これで、完成です！

## さぁ、Bot に話しかけてみよう

初めての方に話しかけるのは緊張しますよね！
ここはビシッと！格好よく！トークしましょう！
![1574917495.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/b1654a79-2f2b-9e60-2dd2-5df102510190.png)

```
{ type: 'message',
  source: { accountId: 'xxxxx@yyy-zzz', roomId: '26280667' },
  createdTime: 1574917451022,
  content: { type: 'text', text: 'hogehoge' } }
```

送ったメッセージが `app.js` のコンソール画面に表示されましたね。
成功です！(*'▽')やったー

#おわりに
ここまでお付き合いいただきありがとうございました。

改めて、LINEWORKS Advent Calendar 2019 の３日目として参加させていただきありがとうございました。
少しはかしこまって書こうかな？とか考えていたのですが、結局いつも通りのテンションでした(=ﾟωﾟ)
本当に申し訳なく思っておりますまる。

５日目にもエントリーしてるので、またどうぞよろしくお願いします～('ω')

ではまた！(^^)/

#参考にさせていただきましたm(_ _)m
[Express 公式ガイド](https://expressjs.com/ja/guide/routing.html)
[ngrok Documentation](https://ngrok.com/docs)
[LINEWORKS Developers](https://developers.worksmobile.com/jp/document?lang=ja)