DEV Community

loading...
Cover image for Write and deploy Golang Telegram Bot

Write and deploy Golang Telegram Bot

talentlessguy profile image v 1 r t l Updated on ・5 min read

Introduction

Most of the tutorials use Python for writing bots because it is rather simple and also almost everyone knows Python. But what about other languages? Maybe someone doesn't like Python or it is slow for some tasks? In this tutorial I'll show how to build a telegram bot with Go and deploy it on Heroku.

Install the things

All the instructions will be for Linux based distros because the author uses Linux (Ubuntu)

You need to install Go:

# Debian / Ubuntu

sudo add-apt-repository ppa:longsleep/golang-backports
sudo apt-get update
sudo apt-get install golang-go

# Fedora

sudo dnf install golang

# Arch
sudo pacman -S go

# OpenSUSE
sudo zypper install golang
Enter fullscreen mode Exit fullscreen mode

For other platforms, see Download page.

Once Golang is set up, let's create a new project.

First, we should create a repo on GitHub, then initialize go module and then download telebot (go library for writing bots) and create our golang code file:

git clone https://github.com/<USER>/golang-tg-bot
cd golang-tg-bot
# Enter github URL of ur repo or any random name
go mod init github.com/<USER>/golang-tg-bot
go get -u -v gopkg.in/tucnak/telebot.v2
touch main.go
Enter fullscreen mode Exit fullscreen mode

Getting Telegram Bot Token

Open Telegram app, search for @BotFather and start the chat. Send /newbot command and follow the instructions. After completing the initial steps, you’ll get —

  • your TOKEN
  • telegram bot URL
  • link on docs

If you click the link (e.g. telegram bot URL) you'll see something like this:

Of course not with these wallpapers but you'll definetely see bot name, and a button "Start". If you press /start you'll launch a bot client and nothing will happen. Because we haven't done anything yet! So let's start writing the bot.

Setting up Heroku

On Heroku, create a new app. Then choose production environment.

After clicking on item in this menu, you'll see something like this:

You won't see any logs because we haven't setup our bot.

Go to Settings, there connect your repository to Heroku app:

Now we should add our telegram token and app url to Config Vars. Put your token and name of the app (e.g. <NAME_OF_YOUR_APP>.herokuapp.com) there.

We'll need them when setting webhooks so our bot will behave like a web server.

Configuration is done here, let's go to code!

Configuring Bot

Webhook

We grab environment variables, then setup webhook that will be running on Heroku's app URL.

package main

import (
    "os"
    tb "gopkg.in/tucnak/telebot.v2"
)

func main() {
    var (
        port      = os.Getenv("PORT")       // sets automatically
        publicURL = os.Getenv("PUBLIC_URL") // you must add it to your config vars
        token     = os.Getenv("TOKEN")      // you must add it to your config vars
    )

    webhook := &tb.Webhook{
        Listen:   ":" + port,
        Endpoint: &tb.WebhookEndpoint{PublicURL: publicURL},
    }
}
Enter fullscreen mode Exit fullscreen mode

Configuring telebot

After webhook being set up we can create an instance of our bot. Here we use our webhook as a Poller, a thing that looks for updates.

package main

import (
    "log"
    "os"

    tb "gopkg.in/tucnak/telebot.v2"
)

func main() {
    var (
        port      = os.Getenv("PORT")
        publicURL = os.Getenv("PUBLIC_URL") // you must add it to your config vars
        token     = os.Getenv("TOKEN")      // you must add it to your config vars
    )

    webhook := &tb.Webhook{
        Listen:   ":" + port,
        Endpoint: &tb.WebhookEndpoint{PublicURL: publicURL},
    }

    pref := tb.Settings{
        Token:  token,
        Poller: webhook,
    }

    b, err := tb.NewBot(pref)
    if err != nil {
        log.Fatal(err)
    }
}
Enter fullscreen mode Exit fullscreen mode

Writing handlers

Handlers for commands are pretty much similar to middleware in Node.js but instead of routes we handle commands, like /hello, or /get_apples 10.

Hello World

Our first handler will be "Hello World":

b.Handle("/hello", func(m *tb.Message) {
    b.Send(m.Sender, "Hi!")
})
Enter fullscreen mode Exit fullscreen mode

Let's deploy our bot to check if it works. Push your changes to repository, then go to Heroku and check if app is deployed.

If it is succeeded, then go to Telegram bot and entering /hello. It will output "Hi!".

Getting user input

To get user input, we need to grab m.Text - text of a message. You can also get other info from message struct, check GoDoc.

b.Handle("/hello", func(m *tb.Message) {
      b.Send(m.Sender, "You entered "+m.Text)
})
Enter fullscreen mode Exit fullscreen mode

If you try it, it will output something like:

Any text after the command will also be shown. For text without a command, use Payload:

b.Handle("/hello", func(m *tb.Message) {
       b.Send(m.Sender, "You entered "+m.Payload)
})
Enter fullscreen mode Exit fullscreen mode

Buttons

Telegram bots have different types of buttons, Inline, they are attached to some message, and Reply buttons which appear on your message panel.

We will implement first ones because they are easier to write.

First, let's define the buttons. telebot has a special struct for it, called tb.InlineButton:

inlineBtn1 := tb.InlineButton{
    Unique: "moon",
    Text:   "Moon 🌚",
}

inlineBtn2 := tb.InlineButton{
    Unique: "sun",
    Text:   "Sun 🌞",
}
Enter fullscreen mode Exit fullscreen mode

After defining the buttons, we should write handlers for them. In Telegram API, you need to write a response callback to each button, even if it doesn't show any alerts or anything else. If you don't write callbacks, button callback will be endlessly loading.

b.Handle(&inlineBtn1, func(c *tb.Callback) {
        // Required for proper work
    b.Respond(c, &tb.CallbackResponse{
        ShowAlert: false,
    })
        // Send messages here
    b.Send(c.Sender, "Moon says 'Hi'!")
})
Enter fullscreen mode Exit fullscreen mode

Let's do the same for second button:

b.Handle(&inlineBtn2, func(c *tb.Callback) {
    b.Respond(c, &tb.CallbackResponse{
        ShowAlert: false,
    })
    b.Send(c.Sender, "Sun says 'Hi'!")
})
Enter fullscreen mode Exit fullscreen mode

Cool, now we need to defne a keyboard for buttons. It is a "set" of them that are attached to a message. Even if you have only button you still need to define a keyboard:

inlineKeys := [][]tb.InlineButton{
    []tb.InlineButton{inlineBtn1, inlineBtn2},
}
Enter fullscreen mode Exit fullscreen mode

Here we created an array of arrays of tb.InlineButton which contains one array with type tb.InlineButton which contains our buttons.

One small thing left - a handler for a command, say /pick_time:

b.Handle("/pick_time", func(m *tb.Message) {
    b.Send(
        m.Sender,
        "Day or night, you choose",
        &tb.ReplyMarkup{InlineKeyboard: inlineKeys})
})
Enter fullscreen mode Exit fullscreen mode

Our command is ready, let's test it (you need to push code for Heroku to update the app)!

b.Start()
Enter fullscreen mode Exit fullscreen mode

Conclusion

As you can see our bot is working and has some nice buttons. For other options, such as stickers and sending files, visit repo readme and godoc.

Discussion (10)

pic
Editor guide
Collapse
ajinkyax profile image
Ajinkya Borade

just an update you will need to add b.Start() to actually start listening on the port.

Collapse
talentlessguy profile image
v 1 r t l Author

ah yes, forgot to add, sorry

Collapse
kostyannns profile image
Kostyannns

Привет! Сделал все по вашейинструкции, но при deploy на heroku ловлю такую ошибку
App not compatible with buildpack, поиски в гугле результатов не дали.
Может вы сталкивались с этим?

Collapse
talentlessguy profile image
v 1 r t l Author

Возможно вы выбрали не тот язык для приложения на Heroku. Его можно переключить в настройках

Collapse
kostyannns profile image
Kostyannns

В смысле buildpack?
Попробовал все что нашел, все равно не работает.

Thread Thread
talentlessguy profile image
Collapse
josemyduarte profile image
Josemy Duarte

Great post! I was struggling with how to handle replies from an inlineButton, thx for your post!

Collapse
talentlessguy profile image
v 1 r t l Author

glad that my post helped you!

Collapse
ajinkyax profile image
Ajinkya Borade

Thanks. But can you tell me the name of the game in your wallpaper

Collapse
talentlessguy profile image
v 1 r t l Author

Hyper Light Drifter