はじめに
- 「AWSとGoを勉強したい!」ということで、オウム返しをするLine Botを作成しようと思いました。
- AWSを使ったサーバーレスの基本の勉強にもなってよかったです!
目標
全体の構造
- Lineにメッセージを送ると、LINEプラットフォームは設定されたWebhook URLに対してPOSTリクエストを送信する。
- API Gatewayは、このリクエストをトリガーにLambda関数を実行する。
- Lambda関数はGo言語で書かれたコードを実行する。
作成手順
手順1:LINE Developersの作成とログイン
- 以下のサイトからDevelopersの作成とログインが行えます。
- 作り方がわからない人は以下が参考になります。
- 作成したボットを友達追加しとくと便利です!
手順2:IAMロールの作成
- Lambdaを使う際には、IAMロールを作成して、権限を設定する必要があります。
- 作成しなくてもデフォルトロールが割り振られますが、デフォルトロールに権限のない操作(データベースの読み書きなど)を行うとエラーが出るので、IAMロールをあらかじめ作っておくのがおすすめです。
作成方法
- 「IAM>ロール」からロールを作成する
- 信頼されたエンティティタイプ:AWSのサービス
- サービスまたはユースケース:Lambda
-
AWSLambdaBasicExecutionRole
を検索して付与 - ロール名を任意に設定して作成します。
lambdaの作成
作成方法
- lambda>関数の作成
- 「一から作成」を選択
- 関数名:「EchoLineBotHandler」に設定します。
- ランタイム:「Amazon Linux 2023」に設定します。
- デフォルトの実行ロール変更>既存のロールを使用から、先ほど作成したIAMロールを指定します。
Goコードを作成
- 次にGoでオウム返しするコードを書きます。以下がコードになります。
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/line/line-bot-sdk-go/linebot"
)
type Webhook struct {
Destination string `json:"destination"`
Events []*linebot.Event `json:"events"`
}
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
// LINE Botの初期化
bot, err := linebot.New(
os.Getenv("LINE_CHANNEL_SECRET"),
os.Getenv("LINE_CHANNEL_ACCESS_TOKEN"),
)
if err != nil {
log.Print(err)
return events.APIGatewayProxyResponse{
StatusCode: http.StatusInternalServerError,
Body: fmt.Sprintf(`{"message":"%s"}`, http.StatusText(http.StatusInternalServerError)),
}, nil
}
// リクエストボディを解析
var webhook Webhook
if err := json.Unmarshal([]byte(request.Body), &webhook); err != nil {
log.Print(err)
return events.APIGatewayProxyResponse{
StatusCode: http.StatusBadRequest,
Body: fmt.Sprintf(`{"message":"%s"}`, http.StatusText(http.StatusBadRequest)),
}, nil
}
// イベント処理
for _, event := range webhook.Events {
// イベントが一般的なメッセージイベントの場合
if event.Type == linebot.EventTypeMessage {
switch message := event.Message.(type) {
// メッセージイベントの中身がテキストの場合(画像とかではなく)
case *linebot.TextMessage:
//オウム返し
if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(message.Text)).Do(); err != nil {
log.Print(err)
return events.APIGatewayProxyResponse{
StatusCode: http.StatusInternalServerError,
Body: fmt.Sprintf(`{"message":"%s"}`, http.StatusText(http.StatusInternalServerError)),
}, nil
}
}
}
}
return events.APIGatewayProxyResponse{
StatusCode: 200,
Body: `{"message":"Success"}`,
}, nil
}
func main() {
lambda.Start(handler)
}
手順3:Goコードをzip化
- LambdaにGoコードをアップロードするにはzipファイルである必要があります。
- Goコードをzipファイルにするやり方は環境によって違い、以下のリンクを参考に行うことができます。
私は、windowsでPowerShelです。人によって違うので参考程度に!
# lambdaパッケージをインストール。
# Lambdaと関数コードの間の相互作用を管理するランタイムインターフェイスの実装を提供
go get github.com/aws/aws-lambda-go/lambda
# 実行可能ファイルと必要なファイル群を正しくZIP形式でパッケージングしてくれるツール
go install github.com/aws/aws-lambda-go/cmd/build-lambda-zip@latest
# power shellでビルドした
# このコードの開設は、GPTがしてくれたよ!
$env:GOOS = "linux"
$env:GOARCH = "amd64"
$env:CGO_ENABLED = "0"
go build -tags lambda.norpc -o bootstrap main.go
~\Go\Bin\build-lambda-zip.exe -o myFunction.zip bootstrap
GPTのお言葉
- 環境変数の設定:
$env:GOOS = "linux"
: Goのコンパイルターゲットのオペレーティングシステム(OS)をLinuxに設定します。AWS Lambdaの実行環境はLinuxであるため、これに合わせてコンパイルする必要があります。$env:GOARCH = "amd64"
: コンパイルターゲットのアーキテクチャをamd64(x86_64)に設定します。これは現在のところ、AWS Lambdaでサポートされている主なアーキテクチャです。$env:CGO_ENABLED = "0"
: CGOを無効にします。CGOはC言語のコードをGoコードに組み込むために使用されますが、Lambda環境ではC言語のライブラリを利用することが推奨されていません。これにより、ポータビリティと互換性を高めることができます。- コンパイルコマンド:
go build -tags lambda.norpc -o bootstrap main.go
: Goのビルドコマンドを使用して、**main.go
ファイルから実行可能ファイルをコンパイルします。ビルドタグlambda.norpc
を使用して、特定のLambdaの最適化を有効にする場合があります。出力ファイル名はbootstrap
と指定されています。AWS Lambdaでは、カスタムランタイムを使用する場合、実行ファイルの名前をbootstrap
**にする必要があります。- パッケージングコマンド:
~\Go\Bin\build-lambda-zip.exe -o myFunction.zip bootstrap
: 事前にインストールした**build-lambda-zip
ツールを使用して、bootstrap
実行ファイルを含むZIPファイルを作成します。このZIPファイルは、Lambdaへのアップロードに使用され、myFunction.zip
**という名前で出力されます。
- 「lambda>関数>コード」から、zipファイル化出来たらLambda関数に作成したzipファイルをアップロードします。
手順4:Lambda関数で環境変数を設定
- Goコード内には環境変数を使っているので、環境変数を設定する必要があります。
- 具体的には以下のコード部分です。
os.Getenv("LINE_CHANNEL_SECRET"),
os.Getenv("LINE_CHANNEL_ACCESS_TOKEN"),
- 「lambda>関数>設定>環境変数」から、設定します。
- それぞれの値に関しては、Line Debeloppersから確認できます。
- キー:LINE_CHANNEL_SECRET 値:Line Debeloppersから確認
- キー:LINE_CHANNEL_ACCESS_TOKEN 値:Line Debeloppersから確認
手順5:APIの作成
- 「API Gateway>API」からAPIを作成します。
- APIタイプ:「Rest API」
- API名:「LineEchoAPI」
- 次は「API Gateway>API>リソース」から、リソースを作成します。
- リソース名:「echo」
- CORSにチェックを入れる
- 「API Gateway>API>リソース」から、メソッドを作成します。
- メソッドタイプ:「POST」
- 統合タイプ:「Lambda関数」
- Lambdaプロキシ統合にチェックを入れる
- Lambda関数を、先ほど作った関数に指定
- 「APIデプロイ」を押してデプロイします。
- ステージ名は、開発フェーズならdev、本番ならprodとかおすすめです。
- ステージ:「新しいステージ」
- ステージ名:「dev」
- 最後に、「API Gateway>API>ステージ」から、作成したAPIのURLをコピーしておきます。
手順6:Line DeveloperのWebhookを設定
- 自身のLine Developerから、「Messaging API設定>Webhook設定」を開きます。
- Webhook URL:先ほどコピーしたURL/リソース名
- Webhookの利用にチェックを入れる
手順7:完成!!
- 結構大変でした。。。