DEV Community

Cover image for Build a Discord Bot with Go - Step-by-Step Tutorial via Webhooks
Nik L.
Nik L.

Posted on

Build a Discord Bot with Go - Step-by-Step Tutorial via Webhooks

Check out more articles:

  1. Building a Scalable Notification System with gRPC and Microservices
  2. Adding a Notification Feed in React Websites
  3. A Complete Guide on Notification Infrastructure for Modern Applications in 2023

1. Create a Discord Server

To get started, create a Discord server. This is necessary as you need administrative rights to add a bot to a server.

TDLR Requirement: Ensure you are an admin of the server.

2. Create a Discord Application

Visit Discord Developer Portal to begin creating your bot.

  • Create a new application.
  • Add a bot to the application.
  • Configure the bot settings and upload an image for it.
  • Note down the Application ID.

3. Add bot to your server

To add your bot to the server, follow these steps:

4. Get ready to code

Create the following directory structure:

├── config.json
├── main.go
└── bot
    └── bot.go
└── config
    └── config.go
Enter fullscreen mode Exit fullscreen mode

Initialize your project and install the required packages:

# Replace [YOUR\_USERNAME] and [YOUR\_PROJECT\_NAME] accordingly
$ go mod init github.com/[YOUR\_USERNAME]/[YOUR\_PROJECT\_NAME]
$ go get github.com/bwmarrin/discordgo
Enter fullscreen mode Exit fullscreen mode

5. JSON Configuration

Collect the token and bot prefix information from Steps 1 and 2:

{
    "token": "your_token_here",
    "BotPrefix": "!"
}
Enter fullscreen mode Exit fullscreen mode

5b. config/config.go

package config

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "os"
)

type Config struct {
    Token     string `json:"token"`
    BotPrefix string `json:"botPrefix"`
}

func ReadConfig() (*Config, error) {
    fmt.Println("Reading config.json...")
    data, err := ioutil.ReadFile("./config.json")
    if err != nil {
        return nil, err
    }
    fmt.Println("Unmarshalling config.json...")
    var cfg Config
    err = json.Unmarshal([]byte(data), &cfg)
    if err != nil {
        fmt.Println("Error unmarshalling config.json")
        return nil, err
    }
    return &cfg, nil
}
Enter fullscreen mode Exit fullscreen mode

6. bot/bot.go

package bot

import (
    "fmt"

    "github.com/alfredosa/GoDiscordBot/config"
    "github.com/bwmarrin/discordgo"
)

var BotId string
var goBot *discordgo.Session

func Start() {
    cfg, err := config.ReadConfig()
    if err != nil {
        fmt.Println("Failed reading configuration:", err)
        return
    }

    goBot, err = discordgo.New("Bot " + cfg.Token)
    if err != nil {
        fmt.Println("Failed initializing Discord Session:", err)
        return
    }

    u, err := goBot.User("@me")
    if err != nil {
        fmt.Println("Failed getting current User:", err)
        return
    }

    BotId = u.ID

    goBot.AddHandler(messageHandler)

    err = goBot.Open()
    if err != nil {
        fmt.Println("Failed opening connection to Discord:", err)
        return
    }

    fmt.Println("Bot is now connected!")
}

func messageHandler(s *discordgo.Session, e *discordgo.MessageCreate) {
    if e.Author.ID == BotId {
        return
    }

    prefix := config.BotPrefix
    if strings.HasPrefix(e.Content, prefix) {
        args := strings.Fields(e.Content)[strings.Index(e.Content, prefix):]
        cmd := args[0][len(prefix):]
        arguments := args[1:]

        switch cmd {
        case "ping":
            _, err := s.ChannelMessageSend(e.ChannelID, "Pong!")
            if err != nil {
                fmt.Println("Failed sending Pong response:", err)
            }
        default:
            _, err := s.ChannelMessageSend(e.ChannelID, fmt.Sprintf("Unknown command %q.", cmd))
            if err != nil {
                fmt.Println("Failed sending Unknown Command response:", err)
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

7. Bind everything and start the bot in main.go

package main

import (
    "fmt"
    "github.com/alfredosa/GoDiscordBot/bot"
)

func main() {
    bot.Start()

    <-make(chan struct{})
}
Enter fullscreen mode Exit fullscreen mode

8. Build and run the bot

$ go build
$ ./GoDiscordBot
Enter fullscreen mode Exit fullscreen mode

9. Test the bot

  • Begin a private conversation with the bot and enter !ping, expecting a 'Pong!' response.
  • Mention the bot using '@botname ping', also receiving a 'Pong!' reply.

Similar to this, I personally run a developer-led community on Slack. Where we discuss these kinds of implementations, integrations, some truth bombs, weird chats, virtual meets, and everything that will help a developer remain sane ;) Afterall, too much knowledge can be dangerous too.

I'm inviting you to join our free community, take part in discussions, and share your freaking experience & expertise. You can fill out this form, and a Slack invite will ring your email in a few days. We have amazing folks from some of the great companies (Atlassian, Scaler, Cisco, IBM and more), and you wouldn't wanna miss interacting with them. Invite Form

Top comments (0)