Azure Functionsを使って非同期処理のLINE BOTを作成する

# はじめに

Azure Functionsを使ってオウム返しするLINEのbotを作成しました。
全体のコードは50行程度でした(Node.js）。
![スクリーンショット 2016-10-13 1.16.32.png](https://qiita-image-store.s3.amazonaws.com/0/104863/941ba3ca-f6a3-6bb4-78a0-52a0c34369e9.png)

# Azure Functionsを使う理由

こちらの記事にあるように、BOT実装のアーキテクチャとしては非同期処理が理想的です。
[実運用に向けたLINE BOTサーバの実装例](http://qiita.com/Matanabe/items/92a613411cd051f64cb9)
[大量メッセージが来ても安心なLINE BOTサーバのアーキテクチャ](http://qiita.com/yoichiro6642/items/6d4c7309210af20a5c8f)

非同期処理を実現しようとすると、HTTPリクエストで受け取ったメッセージなどを一度Queueに格納して、リクエストとは別のシーケンスで処理をさせる実装が必要になります。
Azure FunctionsではQueueとして利用できるAzureStorageが用意されていて、データを格納するだけで勝手に非同期処理が実現できます。

Azure Functionsについてはこちらの記事でとても詳しく紹介されています。
[さーばーれす あーきてくちゃ…？　-Azure Functionsでサーバーレスアーキテクチャが何かを理解する記事]( http://qiita.com/hat22/items/f7b2aec5211951dd7622)

# 必要なもの

1. LINE APIの利用アカウント
2. GitHubアカウント
3. Azureのアカウント

# 手順

## LINE APIの利用登録

LINEでBotを作るためにはAPI利用の登録が必要です。
[Messaging APIのご紹介 | LINE Business Center](https://business.line.me/ja/services/bot)

「Channel Access Token」の文字列が必要なので控えておきます。

## Microsoft Azureのトライアルアカウント

Azureを試用するには幾つかの方法がありますが、私が利用したのはVisual Studio Dev Essentialsというサブスクリプションです。
一年間、毎月一定額まで無料枠が用意されています。
[Visual Studio Dev Essentials | Microsoft Azure](https://azure.microsoft.com/ja-jp/pricing/member-offers/vs-dev-essentials/)

## ソースコード

こちらで公開してます。
https://github.com/yorifuji/azure-functions-line-echo-bot

```js:HttpTriggerNodeJS1/index.js
module.exports = function(context, req) {
    context.log('Node.js HTTP trigger function processed a request. RequestUri=%s', req.originalUrl);

    context.bindings.outputQueueItem = req.body;
    
    context.res = { body : "" };
    context.done();
};
```
```js:QueueTriggerNodeJS1/index.js
module.exports = function (context, myQueueItem) {
    context.log('Node.js queue trigger function processed work item', myQueueItem);

    context.bindings.outputQueueItem = myQueueItem;

    context.done();
};
```
```js:QueueTriggerNodeJS2/index.js
var https = require("https");
var url   = require("url");

function post_line(event)
{
    var post_data = JSON.stringify({
        "replyToken" : event.replyToken,
        "messages"   : [ event.message ]
    });
    var parse_url = url.parse("https://api.line.me/v2/bot/message/reply");
    var post_options = {
        host: parse_url.host,
        path: parse_url.path,
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + process.env.LINE_CHANNEL_ACCESS_TOKEN,
            'Content-Length': Buffer.byteLength(post_data)
        }
    };
    var post_req = https.request(post_options);
    post_req.write(post_data);
    post_req.end();
}

module.exports = function (context, myQueueItem) {
    context.log('Node.js queue trigger function processed work item', myQueueItem);
    myQueueItem.events.forEach(event => post_line(event));
    context.done();
};
```

以下の手順はGitHubからAzureにDeployする場合の手順です。予め手元のGitHubアカウントなどにforkしておきます。

## Function Appの作成

Azureのポータル画面からFunction Appを作成します。

「App Service プラン」は「動的」を選択した方が良いようです。
「場所」はどこでも良い気がしますが、東日本が選択可能です。
「メモリ割り当て (MB)」は後から変更できます。

## ソースコードの配置

しばらく待つと構築が終わり、先ほど作成したFunction Appがリソースの一覧画面に表示されます。
名前をクリックするとFunction Appの管理画面が表示されます。

左下の[Function App の設定]を開き[継続的インテグレーションの構成]をクリックします。
[デプロイ]の設定が表示されるので[セットアップ]をクリックして[ソースの選択]からGitHubを選びます。
GitHubとの連携に必要な作業が始まるので必要な情報を入力します。
設定が完了すると、先ほど作成したFunction Appにソースコードが展開されます。
表示が更新されないことがあるのでその場合は一度トップ画面まで戻ると良いです。

GitHubとの連携はこちらの記事が詳しいです。
[Azure Web AppをGitで継続的デプロイする - Qiita](http://qiita.com/gen2-gk/items/659c95a47afb46b81e52)

なお、ソースコードの配置が終わったら連携をオフにしてかまいません。

## 環境変数に登録

左下の[Function App の設定]の画面に戻り、[アプリケーション設定]を開きます。
[アプリ設定]にスクロールして追加の情報としてキーと値に次の内容を入力します。

キー：
LINE_CHANNEL_ACCESS_TOKEN
値：
LINE developersのChannel Access Tokenの値

上記の値はAPIを使ってメッセージにreplyする際に使います。
[API Reference](https://devdocs.line.me/ja/#reply-message)

入力後、別の項目をクリックすると確定します。画面上部に[保存]ボタンがあるので忘れないようにクリックして適用します。

## WebHook URLの設定

Function Appの管理画面に戻り、左側のHttpTriggerNodeJS1を開きます。
[関数の URL:]が表示されるのでその下のURLをメモします。

LINE Developersで管理画面を開き、[Webhook URL]に先ほどメモしたURLをセットして保存します。

以上で設定は完了です。

# 動作

Botを友達に追加して会話してみてください。入力したメッセージが戻ってきます。

なお、Azure Functionsの制限事項？で、一定時間サービスへのアクセスがなくなると、応答に時間がかかることがあります（リプライが帰らないこともあります）。

# 注意事項

紹介したコードは最小限のロジックのみ実装していてセキュリティやエラー処理などは考慮していません。例えば、LINEサーバーからのメッセージであることの検証などが不足しています。

(2016/10/14) 署名検証の実装を行いました。
[LINE Messaging APIでX-Line-Signatureの署名検証を行う(AzureFunctions/Node.js）](http://qiita.com/yorifuji/items/71e31baf896adb69f567)

# まとめ

Azure Functionsを利用してLINEのbotを作成しました。Azureの機能を使うことで、非同期処理をわずかなコードで実現することができました。
汎用的な非同期メッセージ処理にしたつもりなので他のbotの実装にも流用できると思います。

# 予定

- 手順にキャプチャ画像の追加
- キーワードに反応して返信する
- slack版の開発