HerokuとGoでLINEの Messaging API環境を作ってみた


#はじめに
2016年4月、LINEで使えるボットアカウントを自由に開発できる「LINE BOT API」が1万人の開発者に限定公開され、話題になりましたね。
その後、2016年9月29日に開催された「LINE DEVELOPER DAY 2016」において、「[Messaging API](https://business.line.me/ja/services/bot)」として正式リリースされたようです。
それともう一つ、今度「[LINE BOT AWARDS](https://botawards.line.me/ja/)」が開催されます。なんと、優勝賞金は1000万！
4月の時は「ほ〜ん、とりあえずアカウントだけ作っておくかー」と何もせず放置してました(^ ^;)が、「とりあえず触ってみるかー」という感じでセットアップしてみました。


#何ができるの？
公式ページの説明は[コチラ](https://business.line.me/ja/services/bot)。要点をかいつまむと以下のような感じ。

- Messaging APIは、LINEアプリとサーバ間の送受信を行うAPI。
- Messaging APIは、チャットルームにBotを招待することで利用できるようになる。
- Messaging APIは、Reply APIとPush APIで構成されている。
	- Reply API: ユーザの発言を拾って返答するAPI
	- Push API: Botから任意のタイミングでメッセージ送信するAPI



#LINE BOT APIと何が違うの？
公式ページの説明は[コチラ](https://business.line.me/ja/services/bot)。
まず前提として、Messaging API の公開により、LINE BOT API はサービス終了して使えなくなりました。
基本的な部分は一緒ですが、以下のことが追加で出来るようになったようです。

- メッセージタイプの追加
	- 「Confirm Type」：シンプルにyes or noなど２つのアクションを提示する
	- 「Button Type」：画像やテキストなど複数のアクションボタンを組み合わせた
	- 「Carousel Type」：「Button Type」と同様の情報を、横スクロール形式で複数コンテンツを配置できる
- グループ（複数人）トークへの対応
- SDKが6言語に対応（Tipsですが、それぞれの直下にあるexamplesが書き方の参考になります。）
	- [Java](https://github.com/line/line-bot-sdk-java)
	- [PHP](https://github.com/line/line-bot-sdk-php)
	- [Go](https://github.com/line/line-bot-sdk-go)
	- [Perl](https://github.com/line/line-bot-sdk-perl)
	- [Ruby](https://github.com/line/line-bot-sdk-ruby)
	- [Python](https://github.com/line/line-bot-sdk-python)
- 「LINE Notify」：外部Webサービスやアプリケーションなどからの通知を配信できるようになった。現在の連携できる主なサービスは、Github/IFTTT/Mackerel とのこと。



#それでは本題。Let's 環境構築！

##Server側の設定
まずは、サーバを起動するところまでを行います。

###Server環境と使用言語の選定
基本的にはhttps通信が出来れば、オンプレだろうがAWSだろうがGKEだろうが、どんなサーバでも動きますが、今回はHerokuを使おうと思います。Herokuは個人的に、一番敷居が低くて導入しやすいインフラだと思っています。

言語に関しては、Messaging APIがSDKを提供している言語の中から選択して下さい。
つまりHerokuの場合、Perlが使えないので、Java/Go/Ruby/PHP/Python から選択します。
私は今回Goを選択しましたが、他の言語でも設定するポイントは一緒なはずなので、自分の得意な言語に置き換えて読んでいただければと思います。
（ちなみに今回Goは初めて触ります。構文とか稚拙でもご容赦下さいませ。Goだけ触ったことなかったので勉強を兼ねて。。）

###Herokuの起動
とりあえず、[Getting Started on Heroku](https://devcenter.heroku.com/start) を完了させて下さいｗ
簡単にダイジェストを書くと、Goの環境設定やHeroku CLIをインストールした後、以下のコマンドを実行するだけで完了です。

	$ heroku login
	$ go get github.com/heroku/go-getting-started
	$ cd $GOPATH/src/github.com/heroku/go-getting-started
	$ heroku create
	$ git push heroku master


ここまで行うと、サーバが稼働し、URLが発行されます。
https://(インスタンス名).herokuapp.com にアクセスすると、サンプルページが表示できるはずです。
このURLを後ほど使うので、どこかにメモっておいて下さい。


##LINE側の設定
次は、LINE側の設定を行っていきます。
###Messaging APIの始め方
![messaging_api.png](https://qiita-image-store.s3.amazonaws.com/0/18601/6021fa8d-966a-2671-f9a1-2620ab175472.png "messaging_api.png")

まずは[Messaging API](https://business.line.me/ja/services/bot)のページで登録していくのですが、ここでいきなり罠が待ち構えていますｗ
①「Messaging APIを始める」、
②「Developer Trialを始める」
さぁ、どちらでしょう？！
実際にどちらも作成してみた結果、違いは以下の通りでした。

- 「Messaging APIを始める」→　フリープランでLINE@のアカウントが作られる。
- 「Developer Trialを始める」→　Developer TrialでLINE@のアカウントが作られる。

なるほど、プランの違いだったんですね。つまり正解は、
「どちらもMessaging APIを始められるが、まずは開発用なので、「Developer Trialを始める」が正しい。」でした。。。

違いはページ下部の方に書いてある「プラン紹介」を見てもらえば分かりますが、「Developer Trial」は無料でPush APIが使えます。「50人以上の人に見せる必要がある場合 ≒ 商用利用する場合」は、「Developer Trial以外」の選択肢という事ですね。


###各種アカウントの登録
「Developer Trialを始める」を選択した後は、以下の流れ。

+ LINEアカウントでログイン（持ってない場合は、LINEアプリから登録する）
+ 会社/事業者の追加（既に作成済みのものを使う場合は選択するだけでOK）
+ 画像と名前と業種を入力して「申し込む」で、LINE@ アカウントが作成される。
+ 「LINE@ MANAGER」（管理画面）に進み、「APIを利用する」で、Messaging APIが利用可能になる。

うん、色々とLINE独自な名前なので、自分が今何を作っているのか分からない。。　まとめるとこんな関係だと思う。

- LINEアカウント ≒ ユーザ名（または、プログラマー名）
- 会社/事業者 ≒ グループ名
- LINE@アカウント ≒ プログラム名（または、bot名）
- 会社/事業者は、複数のLINEアカウントを所属させることが可能。
- 会社/事業者は、複数のLINE@アカウント を持てる。

ちょっと初見殺しだけど、複数の開発者や複数のアプリを作ろうとしている人には良い仕様と言えますね。

###Messaging APIの紐付け
さて、LINE@アカウントが出来ましたら、次は「LINE@ MANAGER」（管理画面）に進みます。
![LINE__MANAGER.png](https://qiita-image-store.s3.amazonaws.com/0/18601/b3da1f54-62e3-edd3-f1ba-d3a021c01874.png "LINE__MANAGER.png")
「何かが出来なくなるの？」と、ドキッとしますよね。
これはLINE@が元々ビジネス（お店の人）向けのアカウントだからだと思います。
「1:1トーク」も「お店トーク」もマニュアル返信をするための機能です。
Bot（自動返信）とは相容れないものだからOFFにしないと使えないよ。という理屈でしょう。
なので、既に商用でバリバリ顧客とLINE@でやり取りしている人は、別のLINE@アカウントを作って、そちらでBot運用した方が無難でしょう。うーん、罠がいっぱい。。

「APIを利用する」を選択して、先に進みます。
これでMessagingAPIの紐付けが完了しました。次に出てくるのは、Bot設定画面です。
![bot_setting.png](https://qiita-image-store.s3.amazonaws.com/0/18601/0e52fe5a-11bd-8010-789a-6f9057214efa.png "bot_setting.png")
上記キャプチャの設定がオススメです。理由は以下の通り。

- Webhook送信：これは「利用する」一択。そうしないと、サーバにメッセージが送られない。
- Botのグループトーク参加：グループでも使えた方が良いので、「利用する」に。
- 自動応答メッセージ：これがクセモノ！「利用する」にすると、発言の度にテンプレが出るのでOFFにするべき。
- 友だち追加時あいさつ：どっちでも良いが、頻度は高くないのでONにした。

###Messaging APIの設定
さて、一旦「[LINE BUSINESS CENTER](https://business.line.me/ja/)」に戻り、「アカウントリスト」を見ると、今回作成したアカウントに「Messaging API」の項目が追加されています。
![account_list.png](https://qiita-image-store.s3.amazonaws.com/0/18601/fc583865-3869-52c3-6d51-e6a3a4113ee5.png "account_list.png")


「LINE Developers」をクリックして、新設されたDeveloper用の管理画面から、Messaging APIの設定を行っていきます。
以下のキャプチャを参考に設定を行って下さい。

+ 「ISSUE」をクリックすると、Channel Access Token が発行される。
+ 「EDIT」で編集画面に入り、Webhook URLに「https://(最初に作成したサーバのURL):443/callback」と入力して、「SAVE」する。（URIは "/callback" で無くてもよいですが、SDKのexampleに従ってみた。）
+ サーバ側で必要な情報として、「Channel Secret」と「Channel Access Token」の情報が取得できれば完了。


![api_setting.png](https://qiita-image-store.s3.amazonaws.com/0/18601/946bb68b-bd28-0056-cff7-ef90f8448e03.png "api_setting.png")

これにてLINE側の設定は全て完了です！


##再度、サーバ側の設定
ここからは、LINEBOT用にプログラムのカスタマイズを行っていきます。
###Messaging API SDKのインストール
以下のコマンドを実行するだけ。簡単ですね。

	$ go get github.com/line/line-bot-sdk-go/linebot


###Botプログラムの作成
今回は簡単な動作確認ということで、発言をオウム返しするだけのBotを作成します。

	$ cd $GOPATH/src/github.com/heroku/go-getting-started
	$ vi main.go

go-getting-started のプログラム本体である、main.go を編集していきます。
私は、[examples](https://github.com/line/line-bot-sdk-go/blob/master/examples/echo_bot/server.go) を参考にしました。

	package main

	import (
		"log"
		"net/http"
		"os"

		"github.com/gin-gonic/gin"
		"github.com/line/line-bot-sdk-go/linebot"  // ① SDKを追加
	)

	func main() {
		port := os.Getenv("PORT")

		if port == "" {
			log.Fatal("$PORT must be set")
		}

		// ② LINE bot instanceの作成
		bot, err := linebot.New(
			os.Getenv("CHANNEL_SECRET"),
			os.Getenv("CHANNEL_TOKEN"),
		)
		if err != nil {
			log.Fatal(err)
		}

		router := gin.New()
		router.Use(gin.Logger())
		router.LoadHTMLGlob("templates/*.tmpl.html")
		router.Static("/static", "static")

		router.GET("/", func(c *gin.Context) {
			c.HTML(http.StatusOK, "index.tmpl.html", nil)
		})

		// ③ LINE Messaging API用の Routing設定
	    router.POST("/callback", func(c *gin.Context) {
	        events, err := bot.ParseRequest(c.Request)
	        if err != nil {
	            if err == linebot.ErrInvalidSignature {
	                log.Print(err)
	            }
	            return
	        }
	        for _, event := range events {
				if event.Type == linebot.EventTypeMessage {
					switch message := event.Message.(type) {
					case *linebot.TextMessage:
						if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(message.Text)).Do(); err != nil {
							log.Print(err)
						}
					}
				}
	        }
	    })

		router.Run(":" + port)
	}

オリジナルとの差分箇所にコメントを入れました。簡単に解説すると、

- ①で、linebot SDK をimportして、
- ②で、linebot のインスタンスを立ち上げて、
- ③で、Webhookで指定したURIである"/callback" の受け口を用意する。

もう少しだけ③を解説すると、linebot の居る部屋で誰かが発言した内容がここに入ってきます。
今回のプログラムではそのままその内容を返していますが、今後はここをカスタマイズしていきます。

###環境変数の設定
実は、これだけだと不十分な箇所があります。
先ほどの②で記載したos.Getenv("xxx")は、環境変数で指定された設定を利用するという意味なので、環境変数を設定してあげる必要があります。
herokuには、環境変数を渡せる仕組みが用意してあるので、それを使っていきましょう。

	$ heroku config:set CHANNEL_SECRET="(Developer用管理画面で取得したChannel Secretを入力)"
	$ heroku config:set CHANNEL_TOKEN="(Developer用管理画面で取得したChannel Access Tokenを入力)"

もちろん、プログラムに直接書いても動きますが、githubに公開しようと思ったり、他の人と共同作業する際、知られては困る値は、このように環境変数にしておくのがよいでしょう。


###パッケージの依存関係の設定
もう1点、外部パッケージを使う場合、それらを利用するための設定が必要です。Node.jsだとnpm、Rubyだとgemにあたるものですが、Goの場合、godepというのがよく使われるようなので利用していきます。

	$ go get -u github.com/tools/godep
	$ cd $GOPATH/src/github.com/heroku/go-getting-started
	$ godep save ./...
	$ godep go install ./...



###そして、再びデプロイ！
後は変更を反映させれば完了です！

	$ git add .
	$ git commit -m "Some comment."
	$ git push heroku master

デプロイが完了したら、早速試してみましょう！
あなたが作成したBotが友だちとして居るはずなので、同じ部屋に呼び、何か発言してみましょう。
オウム返ししてくれれば成功です！お疲れ様でした m(_ _)m


さぁて環境も出来たことだし、これからプログラム書いていくぞぉーというところですが、
長くなってきたので今回は終わりにしたいと思います。
ある程度ノウハウが溜まってきたら、後編を書く、かも。。。