LineBotAPI+Heroku+docomoAPI+Node.jsで会話できるBotをつくる

トライアルに申し込んだあと一ヶ月くらいまったくさわってなかったので、HerokuとNode.jsでBotを作ってみたときのメモ。

### 使ったもの
* Heroku + Fixie(tricycle)
* Node.js
* docomo雑談対話API

## 1.Heroku
LineBotAPIを使うには、Server IP WhitelistへのIP登録が必要になるため、[Fixie](https://elements.heroku.com/addons/fixie)というHerokuのAdd-onを利用する。
Add-onのインストールが完了したら、発行されたFixie IDを使って

```
curl http://welcome.usefixie.com --proxy http://fixie:<Your Fixie ID>@velodrome.usefixie.com:80
```

をたたくと、Request発行の確認ができる。

## 2.docomo雑談対話API
Botの根幹となる部分は、[docomo雑談対話API](https://dev.smt.docomo.ne.jp/?p=docs.api.page&api_name=dialogue&p_name=api_reference)を利用するため、開発者登録を行う。
アプリケーションを登録すると、APIKeyが取得できる。

## 3.Node.js
実装はNode.jsで行った。

#### requireしたもの
* [Express](http://expressjs.com/): Node.js向けのアプリケーションフレームワーク
* [body-parser](https://github.com/expressjs/body-parser)： 上記ExpressでPOSTを受け取るときに必要なパースをしてくれるミドルウェア
* [request](https://github.com/request/request)：Node.jsでHTTP/HTTPS通信を行うためのクライアントモジュール
* [async](https://github.com/caolan/async)：非同期処理のフロー制御

``` index.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const request = require('request');
const async = require('async');
const status = {}; // context保存用

app.set('port', (process.env.PORT || 5000));
app.use(bodyParser.json());

app.post('/callback', (req, res) => {
  async.waterfall(
    [
      (callback) => {
        // docomo API
        const apiURL = 'https://api.apigw.smt.docomo.ne.jp/dialogue/v1/dialogue?APIKEY=';
        const apiKEY = process.env.DOCOMO_API_KEY;

        const json = req.body;
        const responseMsg = json['result'][0]['content']['text'];

        const docomoOptions = {
          url: apiURL + apiKEY,
          headers: {
            'Content-Type': 'application/json; charset=UTF-8'
          },
          body: {
            utt: responseMsg,
            context: status.context,
            mode: status.mode
          },
          json: true
        }

        request.post(docomoOptions, (err, response, data) => {
          if (!err && response.statusCode == 200) {
            const body = data;
            status.context = body.context;
            status.mode = body.mode;

            callback(null, json, body.utt);
          } else {
            console.log('エラーです！');
          }
        });
      }
    ],

    // LINE BOT
    (err, json, resultMsg) => {
      if (err) {
        return;
      }

      const headers = {
        'Content-Type': 'application/json; charset=UTF-8',
        'X-Line-ChannelID': process.env.LINE_CHANNEL_ID,
        'X-Line-ChannelSecret': process.env.LINE_CHANNEL_SECRET,
        'X-Line-Trusted-User-With-ACL': process.env.LINE_CHANNEL_MID
      };

      const to_array = [];
      to_array.push(json['result'][0]['content']['from']);

      const sendData = {
        'to': to_array,
        'toChannel': 1383378250,           // 固定らしい
        'eventType': '138311608800106203', // 固定らしい
        "content": {
          contentType: 1,
          toType: 1,
          text: resultMsg
        }
      };

      const options = {
        url: 'https://trialbot-api.line.me/v1/events',
        proxy: process.env.FIXIE_URL,
        headers: headers,
        json: true,
        body: sendData
      };

      request.post(options, function(error, response, body) {
        if (!error && response.statusCode == 200) {
          console.log(body);
        } else {
          console.log('error: ' + JSON.stringify(response));
        }
      });
    }
  );
});

// 動作確認用
app.listen(app.get('port'), function() {
  console.log('Node app is running');
});

```

とりあえず上記で、Herokuにデプロイすると会話ができるようになった。

## まとめ
* Node.jsでアプリを作るのがほぼ初めてだったので、デプロイ方法とか、必要なファイルの準備とか基本的な部分でつまずいた。
* Fixieは便利だけど、無料プランだと、月/500リクエストの制限があるので、あくまでもテスト用。
* Botだけど初めて会話が返ってきた時はなんだかんだうれしい！

Node.jsで開発してHerokuにデプロイする方法とかは、別にまとめようと思う。
→[Node.jsでアプリを作ってHerokuにデプロイするときのメモ](http://qiita.com/ryotahirano/items/c5e0b7047c070d8c089c)

参考：[Nodejs+LINE BOTでレストラン検索](http://qiita.com/Enta/items/45d5295e023e24e9ff0b)