Build a Discord Bot with Go - Step-by-Step Tutorial via Webhooks
Tags: go, javascript, beginners, tutorial
Published: 2024-02-14 15:37:19

Check out more articles:

1. [Building a Scalable Notification System with gRPC and Microservices](https://dev.to/suprsend/building-a-scalable-notification-service-with-grpc-and-microservices-l6d)
2. [Adding a Notification Feed in React Websites](https://dev.to/suprsend/adding-a-notification-feed-in-react-websites-4oa0)
4. [A Complete Guide on Notification Infrastructure for Modern Applications in 2023](https://dev.to/suprsend/a-complete-guide-on-notification-infrastructure-for-modern-applications-in-2023-13b9)

---

## 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:

* Collect the Client ID from the General Information section.
* Go to Discord Authorization URL and replace [CLIENT\_ID] with your actual Client ID: <https://discord.com/oauth2/authorize?client_id=[CLIENT\_ID]&scope=bot>
* Select your server and complete the authorization process.

## 4. Get ready to code
Create the following directory structure:

```css
├── config.json
├── main.go
└── bot
    └── bot.go
└── config
    └── config.go
```

Initialize your project and install the required packages:

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

## 5. JSON Configuration
Collect the token and bot prefix information from Steps 1 and 2:

```json
{
    "token": "your_token_here",
    "BotPrefix": "!"
}
```

### 5b. config/config.go

```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
}
```

## 6. bot/bot.go

```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)
			}
		}
	}
}
```

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

```go
package main

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

func main() {
	bot.Start()

	<-make(chan struct{})
}
```

## 8. Build and run the bot

```sh
$ go build
$ ./GoDiscordBot
```

## 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](https://forms.gle/VzA3ST8tCFrxt39U9)