GoとDockerとHerokuでLINEBOTをためしてみる

# はじめに
上記の組み合わせのQiitaの記事がなかったのでまとめてみました。
Git, Docker, Herokuの最低限の知識を前提にしています。

## ディレクトリ構成
linebot_go
| -- Dockerfile
| -- heroku.yml
| -- main.go

# GoとDockerとHerokuの環境を準備する
LINEBOTを導入する前に、まずはこちらの記事を参考にして準備します。
[Goで書いたサーバーをHerokuにDocker Deployする](https://qiita.com/croquette0212/items/2b85aa2c6b2933244f07)

## pushしたらHerokuに自動デプロイされるようにする
上記の記事だと毎回デプロイするのに2コマンドを打たなければいけないので、1コマンドでデプロイできるようにします。

・上記記事（2コマンド）

```
$ heroku container:push web
$ heroku container:release web
```


・1コマンド

```
$ git push heroku master
```

ルートディレクトリに`heroku.yml`を追加します。
内容は以下です。

```yml:heroku.yml
build:
  docker:
    web: Dockerfile
```
参考：[Building Docker Images with heroku.yml](https://devcenter.heroku.com/articles/build-docker-images-heroku-yml)

# LINEBOTを導入する
## LINEアカウント作成、SDKインストール
こちらの記事を参考にして、アカウント作成とSDKのインストールをする。
[Go入門！？LineAPIとGOでオウム返しbotを作る](https://qiita.com/ken1ro/items/2c4cd04bc5433ccbc217)
⇒Lineアカウントの準備、Line SDKのインストール

## main.goを修正
SDKにある以下のサンプルを参考にしてmain.goを修正します。
`line-bot-sdk-go/examples/echo_bot/server.go`

```go:main.go
package main

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

	"github.com/line/line-bot-sdk-go/linebot"
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello world!\n")
}

func lineHandler(w http.ResponseWriter, r *http.Request) {
	bot, err := linebot.New(
		"(自分のシークレットを入力)",
		"(自分のアクセストークンを入力)",
	)
	if err != nil {
		log.Fatal(err)
	}

	events, err := bot.ParseRequest(r)
	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}
	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
				replyMessage := message.Text
				if replyMessage == "ぶりぶり" {
					replyMessage = fmt.Sprintf("あああああああああああああああああああああああああああああああ！！！！！！！！！！！（ﾌﾞﾘﾌﾞﾘﾌﾞﾘﾌﾞﾘｭﾘｭﾘｭﾘｭﾘｭﾘｭ！！！！！！ﾌﾞﾂﾁﾁﾌﾞﾌﾞﾌﾞﾁﾁﾁﾁﾌﾞﾘﾘｲﾘﾌﾞﾌﾞﾌﾞﾌﾞｩｩｩｩｯｯｯ！！！！！！！）")
				}
				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(replyMessage)).Do(); err != nil {
					log.Print(err)
				}
			case *linebot.StickerMessage:
				replyMessage := fmt.Sprintf(
					"sticker id is %s, stickerResourceType is %s", message.StickerID, message.StickerResourceType)
				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(replyMessage)).Do(); err != nil {
					log.Print(err)
				}
			}
		}
	}
}

func main() {
	port, _ := strconv.Atoi(os.Args[1])
	fmt.Printf("Starting server at Port %d", port)
	http.HandleFunc("/", handler)
	http.HandleFunc("/callback", lineHandler)
	http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
}
```

## Dockerfileを修正
そのままのDockerfileだとLINEのSDKがHerokuにインストールされないので以下のコマンドを追記します。
`RUN go get github.com/line/line-bot-sdk-go/linebot`

```dockerfile:Dockerfile
FROM golang:latest as builder

ENV CGO_ENABLED=0
ENV GOOS=linux
ENV GOARCH=amd64
WORKDIR /go/src/github.com/yokoe/go-server-example
COPY . .
RUN go get github.com/line/line-bot-sdk-go/linebot
RUN go build main.go

# runtime image
FROM alpine
COPY --from=builder /go/src/github.com/yokoe/go-server-example /app

CMD /app/main $PORT
```

## Herokuにpush
`git push heroku master`でpush。

## LINE DevelopersのWebhookにHerokuのURLを設定
LINE Developers＞Messaging API設定＞Webhook設定
にHerokuのURLを入力します。
<img width="405" alt="linedev.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113263/81fc3e49-14cf-69b8-5152-8e9f25d508dd.png">


# BOTを友だち追加しておためし！
![30656.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113263/e0f2296a-cc7f-6a74-6abc-b32da865a0c5.jpeg)