🤖

【Go】Discordのbotにボタンをつける方法(ERROR: UNION_TYPE_CHOICESでハマった話)

2022/10/07に公開

discordのbotで、ボタンを付けるのにかなり苦戦したので、記録として残しておきます。
より良い方法があれば、コメントで教えていただけると嬉しいです。

使用するライブラリ

https://pkg.go.dev/github.com/bwmarrin/discordgo

結論

最初に動いたコードを載せておきます。

btnという文字列を入力すると

  • タイトル
  • 本文
  • ボタン

を返してくれるbotです。
※ボタンは押しても何も起こりません。

package main

import (
	"fmt"
	"github.com/bwmarrin/discordgo"
	"github.com/joho/godotenv"
	"log"
	"os"
	"os/signal"
	"syscall"
)

func main() {
	if err := godotenv.Load(".env"); err != nil {
		log.Fatal(fmt.Sprintf(".envを読み込めません: %v", err))
	}

	var Token = "Bot " + os.Getenv("APP_BOT_TOKEN")

	session, err := discordgo.New(Token)
	session.Token = Token
	if err != nil {
		log.Fatalln(err)
	}

	//イベントハンドラを追加
	session.AddHandler(Handler)

	if err = session.Open(); err != nil {
		log.Fatalln(err)
	}

	defer func() {
		if err = session.Close(); err != nil {
			log.Fatalln(err)
		}
		return
	}()

	stopBot := make(chan os.Signal, 1)
	signal.Notify(stopBot, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
	<-stopBot

	return
}

func Handler(s *discordgo.Session, m *discordgo.MessageCreate) {
	const CMD = "btn"

	if m.Content != CMD {
		return
	}

	// ボタン付きのメッセージを送信
	{
		btn := discordgo.Button{
			Label:    "ラベル",
			Style:    discordgo.PrimaryButton,
			CustomID: "abcd",
		}

		actions := discordgo.ActionsRow{
			Components: []discordgo.MessageComponent{btn},
		}

		embed := &discordgo.MessageEmbed{
			Title:       "タイトル",
			Description: "本文",
		}

		data := &discordgo.MessageSend{
			Components: []discordgo.MessageComponent{actions},
			Embed:      embed,
		}

		_, err := s.ChannelMessageSendComplex(m.ChannelID, data)
		if err != nil {
			log.Fatalln(err)
		}
	}
}

どこでハマったか?

ハマった原因としては、dataComponentsスライスに直接btnを入れており、actionsを噛ませることをしていなかったからです。

		// ここです
		actions := discordgo.ActionsRow{
			Components: []discordgo.MessageComponent{btn},
		}

これをしないと、以下のようなエラーが発生し、typeが1以外はNGだと怒られます。
型としてはButton型を直接MessageComponent型のスライスに入れることは可能ですが、actionsを噛ませることが重要です。

2022/10/07 01:03:30 HTTP 400 Bad Request, {"code": 50035, "errors": {"components": {"0": {"_errors": [{"code": "UNION_TYPE_CHOICES", "message": "Value of field \"type\" must be one of (1,)."}]}}}, "message": "Invalid Form Body"}

(追記)ボタンクリックで返信を表示

ボタンがクリックされたら、クリックした人しか見られないメッセージを送信するコードを書きましたので、追記します。
session.AddHandler(InteractionHandler)のような感じで、ハンドラを追加して使用します。

func InteractionHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
	if i.MessageComponentData().CustomID == "abcd" {
		resp := &discordgo.InteractionResponse{
			Type: discordgo.InteractionResponseChannelMessageWithSource,
			Data: &discordgo.InteractionResponseData{
				Flags:   discordgo.MessageFlagsEphemeral,
				Content: "レスポンスです",
			},
		}
		if err := s.InteractionRespond(i.Interaction, resp); err != nil {
			log.Fatalln(err)
		}
	}
}

以上

Discussion