こんにちは。
…さて、日が経ってしまいましたが、前回 の続きでAPI GatewayからSlack通知を行った作業ログを残していきたいと思います。先週のうちに書いておく予定だった!!
前回の記事
API Gateway->Lambdaを経てSlackのWebhookURLへ送信する-その1- – Shimabox Blog
やったこと
- API Gatewayでエンドポイントを作成 ← 今回の対象
- API GatewayのトリガーとしてLambdaを作成 ← 今回の対象
- このLambdaからSlackのWebhookURLに送信 ← 今回の対象
- Slack Appの
Incoming Webhooksを利用 ← 前回の記事参照
- Slack Appの
直接、WebhookURLにcurlで送ればいいじゃん!!と思うかもしれませんが、まぁ、あれです、素振りってやつです。大事なことなので前回に引き続き2回。
じゃあやってみましょう!今回はプログラミングしていきますよ!
免責
今回はAWSでの作業もありますが、お試し実装ということもありPowerUserAccess,IAMFullAccessで作っているので、そこらへんは察してください。
本来であれば権限を絞って設定するのがいいです。
APIGatewayとLambdaの使用なので、そんなにお金はかからないと思いますが、無茶はやめておきましょう。
AWSでの作業
ユーザーを用意
とりあえず作業用ユーザー、ユーザーグループを作成します。
上でも述べましたが、ユーザーグループにはPowerUserAccess, IAMFullAccessを付与しています。
作業用ユーザー(api-gateway-userとしました)は、このユーザーグループに追加しておきます。
以降、このユーザーで作業をしていきます。
ロールを作成
同じく、IAMからロールの作成より以下のロールを作成します。
Lambdaを作るときに、お任せするのもありですが名前をつけておきます。
- ロール名
- 任意
- ここでは、
api-gateway-to-lambda-roleとしています
- 許可ポリシー
AWSLambdaBasicExecutionRole
Lambdaの作成
APIGatewayに紐付けるLambdaを作成します。
関数作成
- Lambda -> 関数の作成 を開きます
- 以下を入力し、関数の作成 をクリックします
- 関数の作成は、
一から作成を選択 - 関数名
- 任意の関数名を入力
- ここでは、
notification-to-slackとしました
- ランタイム
Go 1.xを選択
- アーキテクチャ
x86_64を選択
- デフォルトの実行ロールの変更
-
既存のロールを使用するを選択し、ロールを作成で作成したロール(api-gateway-to-lambda-role)を選択
-
- 関数の作成は、
ハンドラ名修正
※ ビルド時に、バイナリ名をhelloにして利用するのならこの作業は要りません
ランタイム設定の編集から、
ハンドラ名を main に変えて保存します。
環境変数の設定
環境変数の編集より、
以下の環境変数を設定して、保存します。
- キー
- SLACK_WEBHOOK_URL
- 値
Incoming Webhooksで発行したURL- 前回の記事 を参考にしてみてください
いったんここで、Lambdaの作成は止めておきます。あとでソースを書きます。
APIGatewayの作成
構築
API Gateway -> APIを作成 を開き、APIタイプを選択より、HTTP APIを選択し、構築をクリックします。

REST API使ったほうがいいのでは?と思うかもしれませんが、パッと試すためHTTP APIを利用します。
APIの作成
以下を入力し、次へをクリックします。
- 統合を追加
- Lambda を選択
- Lambda関数
- Lambda関数の作成で作成したLambda関数(notification-to-slack)を選択
- API名
- 任意の名前を入力
- ここでは、
notification-to-slack-apiとしました
ルートを設定
ステージを定義
お試しなのでステージ名そのまま、自動デプロイを有効にしたまま、次へをクリックします。
開発用、本番用など分けたい場合は、自動デプロイは外して名前をつけておくといいと思います。

確認して作成
これで、APIGatewayの作成は完了です。
Lambdaの確認
作成したLambdaに戻り、設定 -> トリガー を確認してみると、上記で作成したAPIGatewayと紐づいていることがわかると思います。エンドポイントの確認も出来ますね。
Lambda関数の作成
いよいよ、Lambda関数の作成を行います。Goで書きます。
Goのバージョンは、1.20.4です。
go version go version go1.20.4 darwin/amd64
前準備
適当にディレクトリを作って、
mkdir notification-to-slack cd notification-to-slack
go mod init しておきます。
go mod init notification-to-slack go: creating new go.mod: module notification-to-slack
Go の AWS Lambda 関数ハンドラー – AWS Lambda に則り、github.com/aws/aws-lambda-go/lambdaをインストールしておきます。
go get github.com/aws/aws-lambda-go/lambda go: downloading github.com/aws/aws-lambda-go v1.41.0 go: added github.com/aws/aws-lambda-go v1.41.0
events package – github.com/aws/aws-lambda-go/events – Go Packages
コード
以下のjsonがPOSTされることを想定したコードを書きます。
{
"name": "shimabox",
"favorite_foods": [
"ゴーヤーチャンプル",
"マンゴー"
]
}
main.go
main.go を作成します。
package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
"strings"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
type myEvent struct {
Name string `json:"name"`
FavoriteFoods list `json:"favorite_foods"`
}
type list []string
type requestBody struct {
Blocks []block `json:"blocks"`
}
type block struct {
Type string `json:"type"`
Text textType `json:"text"`
}
type textType struct {
Type string `json:"type"`
Text string `json:"text"`
}
func handler(r events.APIGatewayProxyResponse) error {
// BodyにPOSTデータが入っているので構造体に変換
var event myEvent
err := json.Unmarshal([]byte(r.Body), &event)
if err != nil {
return err
}
// Slackへ送信するリクエストボディを作成
body := &requestBody{
Blocks: []block{
{
Type: "section",
Text: textType{
Type: "mrkdwn",
Text: fmt.Sprintf("こんにちは `%v` さん:smile:", event.Name),
},
},
{
Type: "section",
Text: textType{
Type: "plain_text",
Text: "そうですか、",
},
},
{
Type: "section",
Text: textType{
Type: "plain_text",
Text: toListNotation(event.FavoriteFoods),
},
},
{
Type: "section",
Text: textType{
Type: "plain_text",
Text: "が、好きなんですね!",
},
},
},
}
bodyBytes, err := json.Marshal(body)
if err != nil {
return err
}
// 環境変数からWebhook用エンドポイントを取得
endpoint := os.Getenv("SLACK_WEBHOOK_URL")
// リクエストを生成
req, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewBuffer(bodyBytes))
if err != nil {
return err
}
// Headerつけてリクエストを投げる
req.Header.Add("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
// Slackからのレスポンス判定
if res.StatusCode != http.StatusOK {
b, err := io.ReadAll(res.Body)
if err != nil {
return err
}
return errors.New(fmt.Sprintf("error!! code: %d, body: %v", res.StatusCode, string(b)))
}
return nil
}
func toListNotation(list list) string {
l := len(list)
values := make([]string, 0, l)
for i := 0; i < l; i++ {
values = append(
values,
fmt.Sprintf(`• %v`, list[i]),
)
}
return strings.Join(values, "\n")
}
func main() {
lambda.Start(handler)
}
返り値で、(events.APIGatewayProxyResponse error)とすることもできますが、今回はSlackに送信するだけなので単純にerrorを返すだけにしています。
余談
リストのところは、マークダウンの-でリスト表記出来るかと思いきやまさかの•を書くという力技…
Block Kit Builder – Slack
ガチでやりたい場合は、以下の形式でSlackに投げるとインデントを指定してリスト表記できるようです。
{
"blocks": [
{
"type": "rich_text",
"elements": [
{
"type": "rich_text_list",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": "test"
}
]
}
],
"style": "bullet",
"indent": 0
},
{
"type": "rich_text_list",
"elements": [
{
"type": "rich_text_section",
"elements": [
{
"type": "text",
"text": "test2"
}
]
}
],
"style": "bullet",
"indent": 1
}
]
}
]
}
参考: kotlin – How do I post a bulleted list using the slack api – Stack Overflow
Makefile
Makefileを用意してビルドをちょっと楽にしておきます。
.PHONY: build
build:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main main.go
zip main.zip main
構成
構成はこんな感じです。
tree . ├── Makefile ├── go.mod ├── go.sum └── main.go
これでLambda関数の作成は完了です。
デプロイ
ビルド
goをビルドしてzipを作ります。
make build CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main main.go zip main.zip main adding: main (deflated 45%)
デプロイ
zipが出来たので、Lambdaを開いてコードのアップロード元から.zipファイルを選択します。

アップロードから、zipファイルを選択し保存をクリックします。

関数 notification-to-slack が正常に更新されました。と表示されればOKです。

動作確認
curlでAPIGatewayを叩く
準備が出来たのでコマンドを叩きます。
curl -X POST -H 'Content-type: application/json' \
--data '
{
"name": "shimabox",
"favorite_foods": [
"ゴーヤーチャンプル",
"マンゴー"
]
}' \
https://1234xxxxxx.execute-api.ap-northeast-1.amazonaws.com/notification-to-slack // APIGatewayのエンドポイント
null が返却されれば成功です。
{"message":"Internal Server Error"}みたいなのが返ってきたらログ(CloudWatch)を確認してみてください。
CloudWatch
CloudWatchは以下で確認できると思います。
CloudWatch > ロググループ > /aws/lambda/notification-to-slack(Lambda名)
結果
slackに以下のように投稿されればOKです!
おわりに
というわけで、APIGatewayからLambdaを経由してSlackに投稿するまでを試してみました。
手順はちょっと多くて面倒かもです(AWSのところはCDKとかSAMとか使えばマシになるとは思います)が、1回用意してしまえば色々とお試し出来るのかなぁと思います!
(ちゃんと組むなら、VPCで制限とかIP制限とかしたほうがいいかなぁと思います。そのへん今度やってみよ〜。)













