Node.jsでLINEのボットを作る2017

LINEの[Messaging API](https://devdocs.line.me/ja/)が楽しいので色々いじっていたのですが、大量の接続を安価に捌きたくてAWSのLambdaを使えないか調べてみると、JavaかPythonでないとLambdaで使えるオフィシャルなクライアントライブラリがありませんでした。

| LINE Messaging API       |       AWS Lambda |
|:-----------------|------------------:|
| Java             |              Java |
| Python           |            Python |
| Go           |             C#|
| Perl           |             Node.js|
| Ruby           |             |
| PHP           |             |

ちょっとググった限りだと、有志によってNode.js用のモジュールが公開されていたりもしたのですが、少し内容が古くなっていて、他の言語のようにChannel SecretやChannel Access Tokenによる認証はサポートされていないようでした。LambdaでJavaを扱うのはやや不安があり、まあPythonでもいいのですが、JavaScriptがいつまでも一級市民になれないままでいるのは悲しいので、基本的な機能をまとめてgistに公開しておきました。

https://gist.github.com/yagitoshiro/d4fd6345aab010fbc29b94c02ef50914

Express 4.xで使うようになっています。使い方はとっても簡単。まずは下準備。Messaging APIのアカウント登録は済んでいるものとします。またWebhookもオンになっているものとして進めます。

1. Line developersのページから「Channel Secret」と「Channel Access Token」を取得します。
2. 上のgistのファイルを設置します。下の例では同じディレクトリに置いてあります。
3. サーバ用のファイルを用意しましょう。

```js
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var bot = require('./line_bot');
var LineBot = new bot({
  channelSecret: '<YOUR CHANNEL SECRET>',
  channelAccessToken: '<YOUR CHANNEL ACCESS TOKEN>'
});

app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json({
  verify: LineBot.validate_signature
})); //これでLINEからのアクセスかどうか勝手にチェックしてくれるようになります

app.post('/callback', function(req, res){
  // ここにボットの実際の動作を記述
});

app.listen(process.env.PORT || 4649, function(){
  console.log("Server is running...");
});
```

依存するnpmモジュールはrequestとexpress、body-parserです。

```
$ yarn init
$ yarn add express body-parser request
```

これで準備は完了です。

では、実際にMessaging APIを使ってみましょう。LINEのWebhookから送信されるデータは個別のイベントを含む`events`という配列形式になっています。[詳細はAPIの仕様](https://devdocs.line.me/ja/)をご覧ください。

## reply

まずは返信です。受信するメッセージにはユニークな返信用トークンとして`replyToken`が割り振られていますのでそれを使うだけで簡単に実現できます。

```js
app.post('/callback', function(req, res){
  // ここにボットの実際の動作を記述
  for(var e in req.body.events) {
    if (e.type === 'message') {
      //メッセージが届いたので返信します
      LineBot.reply({
        replyToken: e.replyToken,
        messages: [{type: 'text', text: 'そうですね'}]
      });
    }
  }
});
```

これだけです。APIを叩く場合は基本的に全てPromise対応してあるので、エラー処理や事後処理を追加する場合は`.then(fullfil).catch(reject)`を追加することができます。

## profile

受信したメッセージの送信元ユーザの情報を取得します。

```js
app.post('/callback', function(req, res){
  // ここにボットの実際の動作を記述
  for(var e in req.body.events) {
    LineBot.profile({
      userId: e.source.userId
    })
    .then(function(profile){
      console.log(profile.displayName);
    })
    .catch(function(err){
      console.log(err);
    });
  }
});
```

簡単ですね。`profile.statusMessage`で普段設定している痛いポエムなんかも取得できます。

## push

Developer Trialアカウントや有料アカウントを利用していると返信以外にもフォローされているユーザにメッセージを送信することができます。userIdを保存しておけば実現できますが、ここでは`profile`と組み合わせてみましょう。

```js
app.post('/callback', function(req, res){
  // ここにボットの実際の動作を記述
  for(var e in req.body.events) {
    LineBot.profile({
      userId: e.source.userId
    })
    .then(function(profile){
      LineBot.push({
        to: profile.userId,
        messages: [{type: 'text', text: 'Yo, ' + profile.displayName}]
      });
    })
    .catch(function(err){
      console.log(err);
    });
  }
});
```

こんな感じ。他にもmulticastやleaveにも対応していますが、使っていないので確認していません…ざっと作って公開したので、お気付きの点があれば教えてください。モジュールにしてもいいんですが時間があったらそのうちに、という感じです。チャオ！