IBM Cloud Functionsで作るサーバーレスLINE bot

# 今年もIBM Cloud × LINE bot
去年のアドベントカレンダーでは、[IBM CloudのNode-REDを使ってLINE botを作る方法](https://qiita.com/K_M95/items/16698048d344389d3cf0)を紹介しました。アドベントカレンダーのおかげなのか最近Googleで「Node-RED LINEbot」で検索するとこの記事がトップに表示されるようになりました。Node-REDで簡単にLINE botを作るのもいいですが、IBM CloudのNode-REDの場合、ライトプランだとしばらくフローの編集をしないとアプリが停止してしまい、LINE botが動かないことがしばしばありました。そこで、他の方法でライトプランでも作れるLINE botを考えたときに最近知ったIBM Cloud Functionsを使ってbotを作る方法を思いつきました。他のクラウドベンダーのサーバーレスでもLINE botを作っているわけだから、IBM Cloudでもできないわけがないと思ったので、今回はIBM Cloud Functionsを使ってサーバレスLINE botを作ってみます。

# IBM Cloud CLIのインストール
今回はLINE botのSDKを使うので、コマンドラインでアクションを作成していきます。[こちら](https://cloud.ibm.com/docs/cli?topic=cloud-cli-install-ibmcloud-cli&locale=ja)からコマンドラインツールをインストールします。インストールを終えたらターミナル（Windowsの方はコマンドプロンプト）を立ち上げて、以下のコマンドでIBM Cloudにログインします。

```console
$ ibmcloud login
```

ログインできたらインストール完了です。

# アクションの用意
## 実行環境の用意
LINE botのSDKはIBM Cloud Functionsのデフォルトの環境にはないので、Dockerを使用して環境構築をする必要があります。[こちら](https://qiita.com/K_M95/items/847f8b92dd914ef3b1a1)で環境構築方法を紹介しています。今回は下記のリンクでDocker hubのレポジトリを公開しているので、こちらを使っていきます。こちらの環境はIBM Cloud Functionsのデフォルトで入っているPythonライブラリにLINE botのSDKを入れただけのものです。
[kmiura/linebot_function](https://hub.docker.com/repository/docker/kmiura/linebot_function)

## コードの用意
エディタを開き、以下のコードを保存します。ここでは、ボットに送信したメッセージをそのまま返信するボットではおなじみの「オウム返し」を作成しました。保存する際のファイル名とアクション名は一致している必要があります。ここでは、「first-linebot.py」とします。

```python:first-linebot.py
# coding: utf-8
from linebot import LineBotApi
from linebot.exceptions import LineBotApiError
from linebot.models import TextSendMessage


def main(args):
    print(args)
    # account setting
    line_bot_api = LineBotApi(args['CHANNEL_ACCESS_TOKEN'])

    # make responce
    body = args["events"][0]
    try:
        if body["source"]["userId"] == "Udeadbeefdeadbeefdeadbeefdeadbeef":
            return {"status": 200}
        else:
            line_bot_api.reply_message(
                body["replyToken"],
                TextSendMessage(text=body["message"]["text"]))
    except LineBotApiError as e:
        print("Got exception from LINE Messaging API: %s\n" % e.message)
        for m in e.error.details:
            print("  %s: %s" % (m.property, m.message))
        return {"status": 403}

    return {"status": 200}

```

## アクションの作成
それでは、アクションを作成していきます。まずは、IBM Cloud Functionsのプラグインをインストールしていきます。

```console
$ ibmcloud plugin install cloud-functions
```

以下のコマンドでリソースグループをターゲットします。グループ名に関しては[こちら](https://cloud.ibm.com/functions/learn/cli)からログインして確認します。

```console
$ ibmcloud target -o <org> -s <space> 
```

以下のコマンドでアクションを作成します。

```console
$ ibmcloud fn action create first-linebot --docker kmiura/linebot_function first-linebot.py 
```
エラーなく結果が返ってきたら成功です。

## Webhook URLの生成
これでアクションを作成したので、今度はLINE botに設定するWebhook URLを生成します。ブラウザからIBM Cloudにログインし、IBM Cloud Functionsの画面（ダッシュボード画面のメニューの中のFunctionsまたは機能を選択すると開きます）から先程作成したアクションの設定画面を開きます。```Endpoints```タブをクリックして、```Enable as Web Action```にチェックを入れてセーブしてください。すると、Webアクションを呼び出すことのできるURLが生成されるので、これをコピーします。

![コメント 2019-10-26 194305.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/b536580d-75f2-78fa-587a-2a7fc3afc10a.png)

# LINE botの設定
## LINE Developersでの設定
それでは、LINE botを作成していきます。[LINE Developers](https://developers.line.biz/ja/)にログインし、**新規ブロバイダー→チャンネル作成→Messaging API**に進んで以下の新規チャンネル設定画面まで行き、必要項目を入力してください。

**※任意の項目以外はすべて必須項目です。**
**※アプリ名にはLINEを含む文字列は登録できないので、それ以外の名前を入力してください。**

作成が完了するとチャンネルの設定画面に移動します。この中から「Mesaging API設定」タブを選択し、上に表示されているQRコードから友達追加しておきましょう。スクロールをしてWebhook URLに先程コピーしたFunctionsのURLを貼り付けてください。この時、URLの最後に```.json```
をつけるとWebhookで受け取った値をjsonで取得するのでFunctions側の処理しやすくなります。記入が終わったら「更新」ボタンをクリックして登録完了です。Functionが動作するか確認するときは、「検証」ボタンをクリックします。今回使用したFunctionのコードには、動作確認用のレスポンスも実装しているので、正しく動作していれば「成功」と表示します。
更新後、下に出てくるWebhookの利用は有効にしておきましょう。

![コメント 2019-12-02 233240.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/7d1f1856-f2c8-e30b-f9f1-d2db286c6840.png)

これだけでは、ボットが動きません。更に下に進むと以下のLINE公式アカウント機能が出てきますが、この中の応答メッセージは無効にします。応答メッセージの項目の左側の「編集」をクリックします。

![コメント 2019-12-02 233723.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/106e372e-5f4e-5ad8-be3d-014aa09c0c1d.png)


リンク先の以下の画面から応答メッセージの設定を「無効」にしてください。

![コメント 2019-12-02 234022.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/1a1944c3-1e5b-4ee0-17b6-c0bde8e69e7f.png)

更にスクロールすると、チャンネルアクセストークンの発行欄が出てくるので、「発行」をクリックしてアクセストークンを発行して、メモします。

![スクリーンショット 2019-12-03 00.48.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/e5313b55-a128-41ba-23e1-730f4973aa96.png)


## IBM Cloud CLIの設定
それでは、もう一度ターミナル（windowの方はコマンドプロンプトかPower Shell）を立ち上げて、先程コピーしたアクセストークンをアクションのパラメータとしてCLIから登録します。以下のコマンドで登録します。

```console
$ ibmcloud fn action update YOUR_ACTION --param CHANNEL_ACCESS_TOKEN YOUR_ACCESS_TOKEN
```

# 動作確認
それでは、LINEアプリを開き先程作成したボットのアカウントを開き、送信したメッセージがボットから返ってきたら、正常に動作しています。
<img width="375" alt="IMG_7192.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170520/6f8ad85a-2520-a9a7-74e1-8d480c556b4e.png">

いかがでしたでしょうか？IBM Cloudのサーバレス環境でも簡単にLINE botを作ることができます。そして、IBM Cloud FunctionsならWatson SDKが組み込まれているので、Watsonと連携したボットの作成も簡単です。また、Dockerの知識があれば、環境をカスタマイズできるので、かなり自由度の高いサーバーレスアーキテクチャだと思います。