linebotをgolangで開発した際のTips

初めまして！マレーシアで大学生をしているりゅうじんと申します！
マレーシアに来てから友人との金銭管理をLINEで行いたく思いMessagingAPIを使用したので、その時得たTipsを共有したく思っていました。
その折にアドベントカレンダーの9日目が空いていたので、そこに投稿していきたいと思います。

## Messaging APIとは？
> Messaging APIは、あなたのサービスとLINEユーザーの双方向コミュニケーションを可能にする機能です。

https://developers.line.biz/ja/services/messaging-api/

LINEで受け取った何らかのアクションをきっかけにしてあなたが用意したサーバーに転送して処理を実行できるよ。（意訳）

素晴らしい機能ですね！！これだけでもbotの作り甲斐がありそうです。

さてさてTipsを共有していきたいと思います！！！準備はいいですか！？

## ローカルで開発するにはngrokを使え！
LINEはWebhookである以上、自前で建てたローカルサーバーをWebhookサーバーとして設定することができません。（LINEがどのサーバーに届ければいいかわからないからね）

これはとても困りましたね、、。
変更を加えるたびに開発サーバーにデプロイして検証する。なんてことやっていたら、日が暮れてしまいます。

そこで活躍するのがNgrokというツールになります。
NgrokはローカルPC上で運用されているネットワーク（TCP）サービスを外部に公開することができます。例えば、ローカルPC上のWebサーバを外部から利用可能にすることが可能になります。

つまり、ngrokで発行したURLにアクセスすればローカルホストとLINEの通信が可能になるということ！！！

### Ngrok使い方
macとwindowsそれぞれで説明していきます。
#### macでインストール
```bash:bash
brew install ngrok
```

#### windowsでインストール
https://ngrok.com/

こちらの公式サイトからダウンロードして任意の場所で解凍すればOKみたいです。

### 動かしてみる
インストールできたら、以下のコマンドを参考にして自分の環境で動かせます。

```bash:port8080で動かす
ngrok http 8080
```

これで以下のようなログが出てくるかと思います。
![スクリーンショット 2023-11-22 12.35.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530841/b009f65a-8b44-b158-cf86-6e7132a20887.png)

ここまできたら、LINEのデベロッパーコンソールでWebhook URLをForwardingの値に変更すれば、実機での確認ができます✨

## SDKを使用しよう
Golangで開発をしようと思って一番最初に調べることがSDKだと思います（多分）
ここではざっくりととりあえずこれが必要だよね。みたいな構文を紹介してきたいと思います。

```go:main.go
func main() {
    Secret := os.Getenv("LINE_BOT_CHANNEL_SECRET")
	Token := os.Getenv("LINE_BOT_CHANNEL_TOKEN")
 
    bot, botErr := linebot.New(Secret, Token)
	if botErr != nil {
		return xerrors.Errorf("linebot.New error: %w", botErr)
	}
 
	events, parseErr := bot.ParseRequest(c.Request())
	if parseErr != nil {
		return xerrors.Errorf("bot.ParseRequest error: %w", parseErr)
	}

     for _, event := range events {
         if event.Type == linebot.EventTypeMessage {
             message := event.Message.(*linebot.TextMessage).Text
             if _, err := bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(message)).Do(); err != nil {
						return xerrors.Errorf("reply message err: %w", err)
					}
         }
     }
}
```

ざっくり書いてしまったので解説していきたいと思います。

```go:main.go
    Secret := os.Getenv("LINE_BOT_CHANNEL_SECRET")
	Token := os.Getenv("LINE_BOT_CHANNEL_TOKEN")
    bot, botErr := linebot.New(Secret, Token)
    if botErr != nil {
		return xerrors.Errorf("linebot.New error: %w", botErr)
	}
```

ここでは、Linebotの初期化を行なっています。つまりSDKに対してchannel_tokenとsecret_tokenを渡しています。
そして見慣れた書き方ですが、初期化の際にエラーが起こってしまったら、エラーとして返すといった処理を書いています。一種のエラーハンドリングですね。

```go:main.go
    events, parseErr := bot.ParseRequest(c.Request())
	if parseErr != nil {
		return xerrors.Errorf("bot.ParseRequest error: %w", parseErr)
	}
```

この処理でbotのリクエストをパースしています（説明になっていない気が、）
つまり、LINEから送られてきたイベントをSDKの形に落とし込んで使用しやすくしているんですね！

```go:main.go
    for _, event := range events {
         if event.Type == linebot.EventTypeMessage {
             message := event.Message.(*linebot.TextMessage).Text
             if _, err := bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(message)).Do(); err != nil {
						return xerrors.Errorf("reply message err: %w", err)
					}
         }
     }
```

eventは配列で送られてくるので、一つ一つのイベントを見たいと思ったらforでぶん回さないといけません。なのでこのような形にしています。

このようにすることによってmessageを受け取ることができ、その後に自前の処理を行い結果としてReplyMessageを用いて返すことになります。（今回は使用例だったのでおうむ返しにしています）

とてもシンプルに書くことができてわかりやすいですね！あとは自分で拡張していけば望むBOTが作成できると思います✨

## 今後LINE BOTに期待すること
今回金銭管理のアプリケーションを作成していて欲しい機能がいくつかありましたので一例を紹介させていただきます。

### リプライで削除
作成したアプリケーションではチャットで請求書を発行しているのですが、間違えた時や不要になった際にリプライメッセージでDBからも削除できればとても使用しやすいと思ったのですが、調べてみたところ、まだ公式からも出ていない？みたいだったので、APIとして実装されたらいの一番に作成してみたいです！

## 終わりに
今回初めてLINEのアドベントカレンダーに参加させていただきました！記事を執筆することによって開発したナレッジのシェアだけでなく、自分の記憶の定着化にもかなり寄与したと思います。

素晴らしい１年を幕開けできそうです！！！！！！！
ご精読いただきありがとうございました。

## 参考文献
https://developers.line.biz/ja/services/messaging-api/

https://ngrok.com/

## 筆者
https://twitter.com/ryuji_vlog