slackbot

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 19, 2026 License: MIT Imports: 20 Imported by: 0

README

slackbot-lambda

AWS Lambda 上で Slack Bot を構築するための Go ライブラリです。

API Gateway + Lambda 構成における Slack Event / Interaction の受信・ルーティング・署名検証をサポートします。

Features

  • Event Handler — ジェネリクスによる型安全な Slack Event ルーティング
  • Interaction Handler — BlockActions / ViewSubmission 等の Interaction ルーティング
  • Kingpin Handler — app_mention メッセージを CLI コマンドとしてパース・ディスパッチ
  • Lambda Router — パスベースで Event / Interaction を振り分け
  • Slack Signature Verification — リクエスト署名検証 (Lambda / HTTP ミドルウェア両対応)
  • SSM Parameter Store Loader — シークレットの遅延読み込み・キャッシュ
  • DynamoDB Lock — DynamoDB ベースの分散ロック

Install

go get github.com/kazz187/slackbot-lambda

Quickstart

1. SSM Loader でシークレットを準備する

Slack の Verification Token や Signing Secret を AWS Systems Manager Parameter Store から取得します。

package main

import (
	"context"

	"github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/ssm"
	slackbot "github.com/kazz187/slackbot-lambda"
)

func setupSSM(ctx context.Context) (*slackbot.SSMLoader, *slackbot.SSMLoader, error) {
	cfg, err := config.LoadDefaultConfig(ctx)
	if err != nil {
		return nil, nil, err
	}
	ssmCli := ssm.NewFromConfig(cfg)

	verificationToken := slackbot.NewSSMLoader(ssmCli, "/slack/verification-token")
	signingSecret := slackbot.NewSSMLoader(ssmCli, "/slack/signing-secret")
	return verificationToken, signingSecret, nil
}
2. Event Handler を登録する

RegisterHandler にジェネリクスでイベント型を指定すると、該当イベントが自動的にルーティングされます。

package main

import (
	"context"
	"fmt"

	"github.com/slack-go/slack/slackevents"
	slackbot "github.com/kazz187/slackbot-lambda"
)

func setupEventHandler(verificationToken *slackbot.SSMLoader) *slackbot.EventHandler {
	eh := slackbot.NewEventHandler(verificationToken)

	// @mention イベントを処理
	slackbot.RegisterHandler(eh, func(ctx context.Context, ev *slackevents.AppMentionEvent) error {
		fmt.Printf("Mentioned by %s: %s\n", ev.User, ev.Text)
		return nil
	})

	// App Home を開いたイベントを処理
	slackbot.RegisterHandler(eh, func(ctx context.Context, ev *slackevents.AppHomeOpenedEvent) error {
		fmt.Printf("App Home opened by %s\n", ev.User)
		return nil
	})

	return eh
}
3. Interaction Handler を登録する

ボタンクリックやモーダル送信などの Interaction を ActionID ごとにハンドリングします。

package main

import (
	"context"
	"fmt"

	"github.com/slack-go/slack"
	slackbot "github.com/kazz187/slackbot-lambda"
)

func setupInteractionHandler() *slackbot.InteractionHandler {
	ih := slackbot.NewInteractionHandler()

	ih.EventRoutes.Register(slack.InteractionTypeBlockActions, "approve_button", func(ctx context.Context, action *slack.BlockAction, callback slack.InteractionCallback) error {
		fmt.Printf("Approved by %s\n", callback.User.Name)
		return nil
	})

	ih.EventRoutes.Register(slack.InteractionTypeViewSubmission, "submit_modal", func(ctx context.Context, action *slack.BlockAction, callback slack.InteractionCallback) error {
		fmt.Printf("Modal submitted by %s\n", callback.User.Name)
		return nil
	})

	return ih
}
4. Kingpin Handler でコマンドを定義する (オプション)

@bot help@bot ask ... のように、app_mention メッセージを CLI コマンドとしてパースできます。 kingpin の Command / Flag / Arg がそのまま使えます。

package main

import (
	"context"
	"fmt"

	"github.com/alecthomas/kingpin/v2"
	"github.com/slack-go/slack"
	slackbot "github.com/kazz187/slackbot-lambda"
)

// Command インターフェースを実装
type AskCommand struct {
	question *string
}

func (c *AskCommand) Register(app *kingpin.Application) {
	cmd := app.Command("ask", "ドキュメントに質問する")
	c.question = cmd.Arg("question", "質問内容").Required().String()
	cmd.Action(func(pc *kingpin.ParseContext) error {
		fmt.Println("Question:", *c.question)
		return nil
	})
}

func setupKingpinHandler(slackCli *slack.Client, eh *slackbot.EventHandler) {
	kh := slackbot.NewKingpinHandler(slackCli, "mybot", "My Slack Bot")
	kh.AddCommand(&AskCommand{})

	// EventHandler に登録
	slackbot.RegisterHandler(eh, kh.HandleAppMention)
}
5. Lambda Router で起動する

Event と Interaction のハンドラーを Lambda Router にまとめ、API Gateway からのリクエストをパスで振り分けます。

  • */event → EventHandler
  • */interaction → InteractionHandler
package main

import (
	"context"
	"log"

	"github.com/aws/aws-lambda-go/lambda"
	slackbot "github.com/kazz187/slackbot-lambda"
)

func main() {
	ctx := context.Background()

	verificationToken, _, err := setupSSM(ctx)
	if err != nil {
		log.Fatal(err)
	}

	eh := setupEventHandler(verificationToken)
	ih := setupInteractionHandler()

	router := slackbot.NewRouter(eh.HandleEvent, ih.Handle)
	lambda.Start(router.Handle)
}
5. HTTP ミドルウェアとして使う (Lambda 以外)

net/http や chi などの HTTP サーバーでも署名検証ミドルウェアを利用できます。

package main

import (
	"net/http"

	slackbot "github.com/kazz187/slackbot-lambda"
)

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/slack/event", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})

	handler := slackbot.SlackVerificationMiddleware(func(r *http.Request) (string, error) {
		return "your-signing-secret", nil
	})(mux)

	http.ListenAndServe(":8080", handler)
}

Claude Code Plugin

このライブラリには Claude Code 用のプラグインが同梱されています。インストールすると、Claude Code がこのライブラリの API を理解し、コード生成を支援します。

インストール
# マーケットプレースを追加
/plugin marketplace add kazz187/slackbot-lambda

# プラグインをインストール
/plugin install slackbot-lambda@slackbot-lambda
使い方

インストール後、Claude Code に Slack Bot の実装を依頼すると、このライブラリの API を活用したコードを生成します。

/slackbot-lambda AppMentionEvent を処理して返信する Bot を作って

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNotFoundInteractionType = fmt.Errorf("not found interaction type")
	ErrNotFoundActionValue     = fmt.Errorf("not found action value")
)
View Source
var ErrPermissionDenied = errors.New("permission denied")

Functions

func BlockRetryRequest

func BlockRetryRequest(header http.Header) error

func ConvertHeaders

func ConvertHeaders(headers map[string]string) http.Header

func HandleURLVerification

func HandleURLVerification(body string) (*slackevents.ChallengeResponse, error)

func MustJSONMarshal

func MustJSONMarshal(v any) string

func MustJSONUnmarshal

func MustJSONUnmarshal[T any](data string) T

func NewResponse

func NewResponse(code int) events.APIGatewayProxyResponse

func RegisterHandler

func RegisterHandler[T any](eh *EventHandler, handler EventHandlerFunc[T])

func SlackVerificationMiddleware

func SlackVerificationMiddleware(getSigningSecret func(r *http.Request) (string, error)) func(http.Handler) http.Handler

SlackVerificationMiddleware validates Slack signature for webhook requests

func Verify

func Verify(header http.Header, body []byte, signingSecret string) error

Types

type BotError

type BotError struct {
	Code    Code
	Message string
	Err     error
}

func NewBotError

func NewBotError(code Code, message string, err error) *BotError

func (*BotError) Error

func (be *BotError) Error() string

func (*BotError) Unwrap

func (be *BotError) Unwrap() error

type Code

type Code string
const (
	CodeInternal        Code = "Internal"
	CodeUnauthorized    Code = "Unauthorized"
	CodeInvalidArgument Code = "InvalidArgument"
)

type Command

type Command interface {
	// Register registers the command and its flags/args to the kingpin application.
	Register(app *kingpin.Application)
}

Command is the interface that kingpin subcommands must implement.

type DynamoDBLock

type DynamoDBLock struct {
	DynamoDBCli *dynamodb.Client
	TableName   string
}

func NewDynamoDBLock

func NewDynamoDBLock(dynamoDBCli *dynamodb.Client, tableName string) *DynamoDBLock

func (*DynamoDBLock) AcquireLock

func (dl *DynamoDBLock) AcquireLock(ctx context.Context, userID string, ttl time.Duration) error

func (*DynamoDBLock) ReleaseLock

func (dl *DynamoDBLock) ReleaseLock(ctx context.Context, userID string) error

type EventHandler

type EventHandler struct {
	// contains filtered or unexported fields
}

func NewEventHandler

func NewEventHandler(slackVerificationToken *SSMLoader) *EventHandler

func (*EventHandler) HandleEvent

type EventHandlerFunc

type EventHandlerFunc[T any] func(ctx context.Context, ev T) error

type EventRoutes

func (EventRoutes) Register

func (er EventRoutes) Register(kind slack.InteractionType, actionID string, handler InteractionCallbackHandler)

func (EventRoutes) Run

type InteractionCallbackHandler

type InteractionCallbackHandler func(ctx context.Context, action *slack.BlockAction, callback slack.InteractionCallback) error

type InteractionHandler

type InteractionHandler struct {
	EventRoutes EventRoutes
}

func NewInteractionHandler

func NewInteractionHandler() *InteractionHandler

func (*InteractionHandler) Handle

type KingpinHandler

type KingpinHandler struct {
	// contains filtered or unexported fields
}

KingpinHandler parses Slack app_mention messages as CLI commands using kingpin.

func NewKingpinHandler

func NewKingpinHandler(slackCli *slack.Client, commandName, commandDesc string) *KingpinHandler

NewKingpinHandler creates a new KingpinHandler.

func (*KingpinHandler) AddCommand

func (kh *KingpinHandler) AddCommand(cmd Command)

AddCommand registers a Command to be available for parsing.

func (*KingpinHandler) HandleAppMention

func (kh *KingpinHandler) HandleAppMention(ctx context.Context, ev *slackevents.AppMentionEvent) error

HandleAppMention is an EventHandlerFunc that handles app_mention events.

type LambdaRouter

type LambdaRouter struct {
	EventHandler       LambdaHandler
	InteractionHandler LambdaHandler
}

func NewRouter

func NewRouter(eventHandler, interactionHandler LambdaHandler) *LambdaRouter

func (*LambdaRouter) Handle

type Message

type Message struct {
	Root Root `json:"root"`
}

type Payload

type Payload struct {
	Message Message `json:"message"`
}

type Root

type Root struct {
	User string `json:"user"`
}

type SSMLoader

type SSMLoader struct {
	SSMCli *ssm.Client
	Key    string
	Value  *string
}

func NewSSMLoader

func NewSSMLoader(ssmClient *ssm.Client, key string) *SSMLoader

func NewSSMLoaderMock

func NewSSMLoaderMock(key string, value string) *SSMLoader

func (*SSMLoader) Get

func (l *SSMLoader) Get(ctx context.Context) (string, error)

func (*SSMLoader) MustGet

func (l *SSMLoader) MustGet(ctx context.Context) string

func (*SSMLoader) SetValue

func (l *SSMLoader) SetValue(value string)

SetValue sets the value of the SSMLoader for testing purposes.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL