今やLINE BotやSlack Botなどのチャットボットを開発するのは、エンジニアの嗜みといっても過言ではないくらい当たり前のものになってきました。一方で筆者は恥ずかしながら何だかんだ今までLINE Botを作ったことがなく、先日が初実装でした。
しかし、筆者の構成で作っている最近の記事があまり多くなく動かすまでに予想以上に苦戦しました。ただ苦戦しただけだと辛いだけなので、将来の筆者へのメモとして、また同じような思いをする人が1人でも減ることを願って作成手順を記事化してみました。
つくるもの
LINE Messaging APIを利用して、ありがちなオウム返しbotを
- WSL (Ubuntu 16.04 LTS)
- Go 1.11
- Google App Engine
を使用して実装します。
LINE Messaging APIの構成などについては、公式ドキュメントをご覧ください。
つくる準備
LINE Messaging APIを利用可能な状態にする
まず、LINEBotを利用するために、LINE Developer Consoleにログインし、プロバイダとチャネルを作成します。チャネルを作成する際は、「Messaging APIでチャネル作成する」を選択してください。
このあたりの手順は公式のMessaging APIを利用するにはに詳しく書かれています。
チャネルを作成した後は、チャネルにLINE botとして利用するための設定を行なっていきます。まずは以下の画像のように、アプリ名・説明・業種・メールアドレスの欄を埋めていきます。
それらを埋めた後は、Webhook送信
の欄を利用する
に変更し、自動応答メッセージ
を応答しない
に、友だち追加時あいさつ
を利用しない
に変更します。
また、作ったBotを友達とのグループトークなどに投入したい場合はBotのグループトーク参加
を利用する
に変更しておきます。
あとは、Webhook URL
欄に後述するBotのデプロイ先URLを反映させれば、LINE Developer Console側での設定は完了です。
GAEのセットアップをする
手順としては
- Google Cloud SDKのインストールとセットアップ
- Google App Engineアプリケーションの作成
となります。
1.については、公式のインストールガイドに従ってインストールを行った後、
$ gcloud components install app-engine-go
でGolang用のコンポーネントをインストールすれば完了です。
2.については、公式のApp Engine アプリケーションのプロジェクトとアプリケーションを作成する
を参照すれば完了です。
自分の場合は、WebUI上でプロジェクトを作成した後
$ gcloud app create --project=<PROJECT_ID>
でアプリケーションを作成しました。
つくってみる
LINE BotのアプリをGolangで作成するにあたり、SDKを使用するので、go get
を行なって利用できる状態にします。
$ go get github.com/line/line-bot-sdk-go/linebot
Bot本体のコードを記述する
このコードは基本的にはline-bot-sdk-goに含まれているEchoBotのExamplesを元に記述しています。しかしこのExamplesが書かれたおよそ三年前から現在までの間にGolangやGAEの仕様変更が行われているため、最終的には以下のようなコードに書き換えます。
package main
import (
"fmt"
"log"
"net/http"
"os"
"github.com/line/line-bot-sdk-go/linebot"
"github.com/line/line-bot-sdk-go/linebot/httphandler"
)
func main() {
// HTTP Handlerの初期化
handler, err := httphandler.New(
os.Getenv("CHANNEL_SECRET"),
os.Getenv("CHANNEL_TOKEN"),
)
if err != nil {
log.Fatal(err)
}
port := os.Getenv("PORT")
if port == "" {
port = "8080"
log.Printf("Defaulting to port %s", port)
}
// 実際にRequestを受け取った時に処理を行うHandle関数を定義し、handlerに登録
handler.HandleEvents(func(events []*linebot.Event, r *http.Request) {
bot, err := handler.NewClient()
if err != nil {
log.Print(err)
return
}
for _, event := range events {
if event.Type != linebot.EventTypeMessage {
return
}
switch message := event.Message.(type) {
case *linebot.TextMessage:
replyText := message.Text
if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(replyText)).Do(); err != nil {
log.Print(err)
}
}
}
})
// /callback にエンドポイントの定義
http.Handle("/callback", handler)
// HTTPサーバの起動
log.Printf("Listening on port %s", port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
}
上記コードについて簡単に解説していきます。
LINE Botアプリケーションとして必要な実装は、
- (LINE Bot SDKに含まれている)httpHandlerの初期化
- Handler関数の定義と登録
- HTTPリクエストを処理するエンドポイントの定義
- HTTPサーバの起動
となります。
1.の初期化に関してはhandler, err := httphandler.New()
が
2.の定義と登録に関してはhandler.HandleEvents(func(events []*linebot.Event, r *http.Request) {})
が
3.の定義に関してはhttp.Handle()
が
4. HTTPサーバの起動に関してはhttp.ListenAndServe()
が
それぞれ対応します。
続いて、Handler関数func(events []*linebot.Event, r *http.Request)
の中身について簡単に解説していきます。
LINEのサーバからWebhookで送信されるリクエストは、Webhookイベントオブジェクトに定義されている形式で送られてきます。このリクエストがevents
のSliceの中に格納されているため、そこからリクエストを取り出して逐次処理していきます。
上記のコードの場合、リクエストのイベントタイプ(上記のコードではメッセージイベントであるか)とメッセージイベントの形式(上記のコードではテキストであるか)を判別し、テキストメッセージのイベントであれば、メッセージの中身をmessage.Text
で抜き出して、bot.ReplyMessage().Do()
で返信を作成・送信しています。
ここまでで本体のコードは終わりです。
GAEにデプロイするための設定ファイルを書く
今回はGAEにデプロイするために必須のapp.yaml
に加え、tokenなどを格納するsecret.yaml
を作成します。
runtime: go111
includes:
- secret.yaml
handlers:
- url: /.*
script: auto
secure: always
redirect_http_response_code: 301
env_variables:
CHANNEL_SECRET: "<LINE Developer Consoleのチャネルシークレット>"
CHANNEL_TOKEN: "<LINE Developer Consoleのチャネルアクセストークン>"
app.yaml
のhandlers:
以下は、httpsでの通信を強制する(HTTPで通信した場合HTTPSにリダイレクトさせる)ためのオプションです1。LINE Messaging APIではWebhook接続先にhttps実装を必須としているので、保険の意味も含めてこの設定を適用しています。
secret.yaml
の利用はTOKENなど実行に必要だけど秘匿すべき情報を安全に記述するための方法です2。そのため、secret.yaml
は絶対に.gitignore
に記述し、公開しないようにしてください。
デプロイする
まずは、書いたgoのプログラムをビルドします。
※ 環境によってはexport GO111MODULE=on
をあらかじめ設定する必要があります。3
$ go mod init <YOUR_PROGRAM_PATH>
$ go build
ビルドが完了したら、実際にGAEにデプロイします。
$ gcloud app deploy
$ gcloud app browse
gcloud app browse
の実行後、デプロイ先URLが(おそらくPROJECT_ID.appspot.com
だと思います)表示されるので、最後にLINE Developer ConsoleでWebhook URLにPROJECT_ID.appspot.com/callback
と指定してください。
以上で作業は全て完了です!
完成
無事にデプロイできたら、作ったBotを友だち登録してみて実際に動作確認してみましょう
以下のような形で実行できるはずです。

発展:グループからLINE Botを退出できるようにする
作成したLINE Botは、LINE Developer Console上でBotのグループトーク参加
を利用する
に変更すると、友だちとのグループトークなどにBotを投入して、使用することができます。
しかしながら投入したBotをグループトークなどから退出させる方法は、執筆時点ではBot自らがleave APIを叩いて抜け出すしかないらしいです4。そのためBotがleave APIを叩けるようにあらかじめ実装しておかないと、Botを退出させたいのにできない…!なんて恐れが出てきます。
そこでここでは、実際にleave APIを叩く実装を追加します。
今回実装する仕様としては、
- ユーザから「leave」というテキストメッセージを発した場所がグループトークもしくはトークルームだった場合、Botは該当の会話から退出する
- 上記に該当しない場所で発言された場合、オウム返しを含め何も行わない
でいきます。
Goのコードを追記する
まず、「leave」というメッセージが来た時だけ異なる動作をするために、元のapp.go
のcase *linebot.TextMessage:
の行の直後に、以下のコードを追記します。
if message.Text == "leave" {
leaveGroup(bot, event.Source)
return
}
その後、実際にleave APIを叩く関数leaveGroup()
を追記します。
// グループ・トークルームから退出させる
func leaveGroup(bot *linebot.Client, eventSource *linebot.EventSource) {
switch eventSource.Type {
case linebot.EventSourceTypeGroup:
if _, err := bot.LeaveGroup(eventSource.GroupID).Do(); err != nil {
log.Print(err)
}
case linebot.EventSourceTypeRoom:
if _, err := bot.LeaveRoom(eventSource.RoomID).Do(); err != nil {
log.Print(err)
}
}
}
以上のコードを追記して再デプロイすることで、作ったBotをグループトークでも安心して使用することができます。
最後に
少し手順が多いようにも見えますが、自分は初めてのLINE Botをこのように実装しました。
公式チュートリアルではHerokuを使用していましたが、上記のように実装することで、GAEでもLINE Botを動かすことができるので、Herokuを使ったことない方は、是非こちらの方法も検討してみてはいかがでしょうか。
また、LINEさんの出しているLINEBotの各言語のサンプルを拝見しましたが、個人的にはGolangがかなりシンプルにかけると感じたので、初めて書く方は是非Golangで書いてみるのも良いと思います。