localでLINEMessageAPIを試す(Elixir&Phoenix on mac)

LINEMessageAPIを軽く試してみたかったので, 
クラウドにサーバ立てたり, herokuでもよかったのですがあくまでも軽く試す程度でよかったので調べてみたらローカルでも大丈夫そうなので実装してみました。

トライアルのapiが廃止になり, LINEMessageAPIになったようです。

#LINEでのbotアカウントを作成する。

ここから説明に沿ってbotアカウントを作成していきます。

![スクリーンショット 2017-01-09 23.28.44.png](https://qiita-image-store.s3.amazonaws.com/0/130025/5c79dca5-6cb9-d88a-0359-c754a98535cd.png)

https://business.line.me/ja/services/bot

**Developer Trialを始めるを選ぶ**



![スクリーンショット 2017-01-09 23.32.28.png](https://qiita-image-store.s3.amazonaws.com/0/130025/9a1c6ec8-5c91-73ea-8bc8-97d8bdd701c0.png)

**アカウント名, 他必要事項を入力し登録を完了したらLINE Developersでbotアカウントを設定します。**

![スクリーンショット 2017-01-09 23.35.29.png](https://qiita-image-store.s3.amazonaws.com/0/130025/c2a97a74-385f-5d8e-fdd1-89cf66fb5f91.png)

**Channel Access Tokenを発行し確認しておきます。**

#WebhookURLを設定する

ここからが本題です。

botアカウント宛にmessageが飛んできた時などのeventが発生した際に, MessageAPI側からのPOSTリクエストを受け取るURLを設定します。

今回はlocaltunnelを使い, 発行されるアドレスを指定します。

localtunnelはインターネット上でlocalhostの特定のポートにアクセスできるアドレスを発行できるものです。

```
npm install -g localtunnel
lt -p 4000
your url is: https://sqwtcgvyny.localtunnel.me
```

これで一時的にインターネット上で https://sqwtcgvyny.localtunnel.me でlocalhost:4000にアクセスできるようになりました。

そして今回はlocalhost:4000/callbackをWebhookに使用するので　https://sqwtcgvyny.localtunnel.me/callback を設定します。

#アプリケーションの作成

```
mix phoenix.new linebot
```
phoenixのプロジェクトを作成します。

mix.exsにhttpoisonを追加します。(HttpRequest用)

```mix.exs
def application do
    [mod: {Linebot, []},
     applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext,
                    :phoenix_ecto, :postgrex, :httpoison]]
  end

defp deps do
    [{:phoenix, "~> 1.2.1"},
     {:phoenix_pubsub, "~> 1.0"},
     {:phoenix_ecto, "~> 3.0"},
     {:postgrex, ">= 0.0.0"},
     {:phoenix_html, "~> 2.6"},
     {:phoenix_live_reload, "~> 1.0", only: :dev},
     {:gettext, "~> 0.11"},
     {:cowboy, "~> 1.0"},
     {:httpoison, "~> 0.9.0"}
     ]
end
```

どちらにもhttpoisonを追加します。

```
mix deps.get
```

でmoduleを取得します。

次に実装に入っていきます。

まずlocalhost:4000/callbackでPOSTリクエストを受け付けるようにルーティングを設定します。

そしてこの場合Webhookを使用するのでprotect_from_forgeryをコメントアウトしてcsrf対策を解除します。

```Elixir
defmodule Linebot.Router do
  use Linebot.Web, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    #plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  scope "/", Linebot do
    pipe_through :browser # Use the default browser stack
    get "/", PageController, :index
    post "/callback", CallbackController, :callback
  end
end
```

次にControllerを実装していきます。

```Elixir
#web/controllers/linebot_controller.ex
defmodule Linebot.CallbackController do
  require HTTPoison
  use Linebot.Web, :controller

  def callback(conn, result) do
    message = List.first(result["events"])

    %{ replyToken: message["replyToken"],
      messages: [
        %{ "type": message["message"]["type"], "text": message["message"]["text"] }
      ]
    }
    |> Poison.encode!
    |> reply

    send_resp(conn, 200, "")
  end

  defp reply(json) do
    endpoint_uri = "https://api.line.me/v2/bot/message/reply"
    headers = %{
      "Content-Type" => "application/json; charset=UTF-8",
      "Authorization": "Bearer {CHANNEL_ACCESS_TOKEN}"
    }

    case HTTPoison.post(endpoint_uri, json, headers) do
      {:ok, %HTTPoison.Response{body: body}} -> IO.puts body
      error_message -> IO.puts error_message
    end
  end
end
```

コードの流れとしては, 

1. POSTリクエストを受け取る。
2. データをパースし, 必要なreplyTokenを取得し, messageのtype, textをおうむ返しのためにそのまま使い, jsonにエンコードする。
3. headerにContent-Typeを指定, 先ほど確認したCHANNEL_ACCESS_TOKENをセットする。
4. jsonにエンコードしたデータを https://api.line.me/v2/bot/message/reply にPOSTする。
5. responseをConsoleにputする

この流れになっています。

#Botを動かしてみる

1. コマンドラインで`mix phoenix.server`でcowboyを起動します。この時点でlocalhost:4000でアクセスできる段階になっています。
2. 別タブで`lt -p 4000`を実行します。帰ってきたURLをWebhookURLに登録します。
3. 自分のLINEアカウントでQRコードから登録をし, トークを始める。


<img width="375" alt="S__3751954.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/130025/495dac62-0ce3-3335-c011-3fe06f1521fb.jpeg">


とりあえずMesssagingAPIを試すことができたのでとりあえずよかった。