14
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

GolangとGoogle App Engineを使ってLINEBotを作ってみる

Last updated at Posted at 2019-05-04

今や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として利用するための設定を行なっていきます。まずは以下の画像のように、アプリ名・説明・業種・メールアドレスの欄を埋めていきます。
img2.PNG

それらを埋めた後は、Webhook送信の欄を利用するに変更し、自動応答メッセージ応答しないに、友だち追加時あいさつ利用しないに変更します。
また、作ったBotを友達とのグループトークなどに投入したい場合はBotのグループトーク参加利用するに変更しておきます。
img4.PNG

あとは、Webhook URL欄に後述するBotのデプロイ先URLを反映させれば、LINE Developer Console側での設定は完了です。

GAEのセットアップをする

手順としては

  1. Google Cloud SDKのインストールとセットアップ
  2. 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の仕様変更が行われているため、最終的には以下のようなコードに書き換えます。

app.go
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アプリケーションとして必要な実装は、

  1. (LINE Bot SDKに含まれている)httpHandlerの初期化
  2. Handler関数の定義と登録
  3. HTTPリクエストを処理するエンドポイントの定義
  4. 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を作成します。

app.yaml

runtime: go111

includes:
- secret.yaml

handlers:
- url: /.*
  script: auto
  secure: always
  redirect_http_response_code: 301
secret.yaml
env_variables:
  CHANNEL_SECRET: "<LINE Developer Consoleのチャネルシークレット>"
  CHANNEL_TOKEN: "<LINE Developer Consoleのチャネルアクセストークン>"

app.yamlhandlers:以下は、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.gocase *linebot.TextMessage:の行の直後に、以下のコードを追記します。

app.go
if message.Text == "leave" {
	leaveGroup(bot, event.Source)
	return
}

その後、実際にleave APIを叩く関数leaveGroup()を追記します。

app.go
// グループ・トークルームから退出させる
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で書いてみるのも良いと思います。

参考文献

  1. app.yaml リファレンス

  2. GAE で秘匿したい環境変数を安全に設定する

  3. Go Modules

  4. LINEの新しいMessaging APIを試してみた

14
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?