Goで作ったLINE BotをAzure WebAppsにホスティングしてみる  #linebot


GoとLINE BotとAzureの話です。
意外とWebAppsでGoを動かすチュートリアルが無いので書いてみました。

>アドベントカレンダー遅刻です すみません汗

前に「[GoとlocaltunnelでLine Messaging APIを使ってオウム返しLINE Botを試す #golangjp](http://qiita.com/n0bisuke/items/f0bfa0ead9f59ea81f37)」の記事でlocaltunnelを使ってGoからLINE Messaging APIを使う記事を書きました。

[localtunnel](https://localtunnel.github.io/www/)はハローワールドにはいいですが、実際の運用には適していません。今日は[WebApps](https://docs.microsoft.com/ja-jp/azure/app-service-web/app-service-web-overview)にホスティングしてみたいと思います。

[Running Go on Azure App Services](https://michael-mckenna.com/running-go-on-azure-websites/)を参考に進めます。

## WebAppsでアプリケーションを作る

まずはインスタンス立ち上げですが、管理画面からぽちぽちとボタン押せばいけます。

[Azure Web AppsにGitHub経由でNode.jsアプリケーションをデプロイする仕組みを無料で作る](https://liginc.co.jp/314601)とほぼ同じ内容でいけます。

![](https://qiita-image-store.s3.amazonaws.com/0/35387/f0586e0b-465f-17a9-5114-02552996ecca.png)

URLにアクセスするとこういう画面が表示される状態まで進めましょう

## server.goを作成してデプロイ

アプリケーションのメインになる`server.go`を作成します。
ファイル名は`server.go`じゃないと動かない(かも)です。

* server.go

```server.go
package main  
import (  
    "fmt"
    "net/http"
    "os" 
)

func handler(w http.ResponseWriter, r *http.Request) {  
    fmt.Fprintf(w, "Hi there - this page was served using Go \\o/")
}
func main() {  
    http.HandleFunc("/", handler)
    http.ListenAndServe(":"+os.Getenv("HTTP_PLATFORM_PORT"), nil)
}
```

作成した`server.go`を「[Azure Web AppsにGitHub経由でNode.jsアプリケーションをデプロイする仕組みを無料で作る](https://liginc.co.jp/314601)」を参考にGitHub経由でデプロイ設定をします。

![](https://i.gyazo.com/b52c21b2ca6f4b076e8101b55495fc05.png)

URLを叩いて`Hi there - this page was served using Go \\o/`というテキストが表示されてれば成功です。

![](https://i.gyazo.com/732e2a5299d16029c9b78ec156fd241c.png)

## LINE Botのホスティングに使う

### WebAppsの環境変数にLINEのトークンを設定

[GoとlocaltunnelでLine Messaging APIを使ってオウム返しLINE Botを試す #golangjp](http://qiita.com/n0bisuke/items/f0bfa0ead9f59ea81f37)をもとにLINE Botを作りましょう。

LINEのBot管理画面から以下の二つの値をメモしておきましょう。

* Channel Secret
* Channel Access Token

![](https://i.gyazo.com/cd3f11fe22d28e22171ff3633258d916.png)

この二つの値は外部に知られるとまずいので、ソースコードに入れずに環境変数に埋め込みます。
WebAppsの管理画面の`アプリケーション設定 > アプリ設定`にキーと値を設定します。

![](https://i.gyazo.com/05fbca2a420b5f4195e543c93a33caaa.png)

### server.goを変更

`server.go`を以下に変更しましょう。

`os.Getenv("LINE_CHANNEL_SECRET")`と`os.Getenv("LINE_CHANNEL_ACCESS_TOKEN")`の部分で先ほど設定した値を呼び出しています。それ以外は[前回記事](http://qiita.com/n0bisuke/items/f0bfa0ead9f59ea81f37)と同様です。

* server.go

```server.go
package main  
import (  
    "fmt"
    "net/http"
    "os" 
    "log"

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

func handler(w http.ResponseWriter, r *http.Request) {  
    fmt.Fprintf(w, "Hi there - this page was served using Go \\o/")
}
func main() {
    bot, err := linebot.New(
		os.Getenv("LINE_CHANNEL_SECRET"),
		os.Getenv("LINE_CHANNEL_ACCESS_TOKEN"),
	)
	if err != nil {
		log.Fatal(err)
	}

    http.HandleFunc("/", handler)
	// Setup HTTP Server for receiving requests from LINE platform
	http.HandleFunc("/callback", func(w http.ResponseWriter, req *http.Request) {
        fmt.Printf("ping\n")
		events, err := bot.ParseRequest(req)
		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:
                    fmt.Printf("%v", message)
					if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(message.Text)).Do(); err != nil {
						log.Print(err)
					}
				}
			}
		}
	})
    
	// This is just a sample code.
	// For actually use, you must support HTTPS by using `ListenAndServeTLS`, reverse proxy or etc.
    fmt.Printf("サーバーを起動しています...")
    
	if err := http.ListenAndServe(":"+os.Getenv("HTTP_PLATFORM_PORT"), nil); err != nil {
		log.Fatal(err)
	}
}
```

ちなみに外部モジュールの読み込みについては特に設定がいらずに、 **go getコマンドの作業はWebApps側が自動的にやってくれます。** 便利ですね。

### Callback URLを設定

LINE Botの設定に`https://xxxxxxx/callback`を設定しましょう。
(先ほどの画像の青枠で囲まれてる部分)

`server.go`内の`/callback`にハンドリングしてる関数がBotに話しかけた際に呼ばれるようになります。

```server.go
 http.HandleFunc("/callback", func(w http.ResponseWriter, req *http.Request) {
 ・
 ・
 (ここがLINE Botに話掛けた時に呼ばれるようになる箇所)
 ・
 ・
 }
```

### 試す

更新したら再度デプロイしてLINE Botの挙動を確認してみましょう。

![](https://i.gyazo.com/6ff4e1797012e0d3d4a6470f903469e4.png)

無事にホスティングされるとこんな感じでオウム返ししてくれます。

## おわりに

こんな感じでGoで作ったLINE BotとAzure WebAppsにホスティングして運用準備を整えることができました。

本当は[Introduction to App Service on Linux](https://docs.microsoft.com/ja-jp/azure/app-service-web/app-service-linux-intro)の新WebAppsを試してみたかったけどうまくいかなかったので別の機会に再チャレンジします。