DEV Community

Krishnanand
Krishnanand

Posted on • Updated on

Simple Telegram Bot in Go

The adoption of chat-bots are at a peak now. Since facebook opened up its developer platform and opened the world of possibilities for chat-bots many platforms supported bots. Telegram is one of the leading platforms with bot functionality.

There is almost a bot for everything on telegram. For memes, searching movies, downloading youtube videos, dating and many more. Businesses engage with users through these bots. Crypto companies do airdrops, giveaways using these bots. Bots are literally everywhere.

Today we are going to checkout how to build a telegram bot using Golang. So if you don't know Go this article is not for you.
We are not using any telegram bot api wrapper libraries .We are using only the net/http package to have a better understanding how things work under the hood. Let's dive right in.

Getting started

First thing you have to do is to get a bot token after creating a bot using botfather bot on telegram and declare a constant.

const botToken = "BOT_TOKEN"
Enter fullscreen mode Exit fullscreen mode

Let's start by creating a main.go file.

The first thing we need is the net/http package we also require the log package for logging the errors so import them and code the main function which looks like this.

func main() {
    err := http.ListenAndServe(":8080", http.HandlerFunc(webHookHandler))
    if err != nil {
        log.Fatal(err)
        return
    }
}
Enter fullscreen mode Exit fullscreen mode

Yep that's it . That' how much it takes to make a simple http server in go.It listens at the port 8080 and invokes the function webHookHandler on recieving a http Request the next line is just how we handle errors in go.

Now that we have setup a server we want to create the webHookHandler function. You may think why the name webHookhandler its because we are using the webHooks. You can find more details here on Telegram bot docs.

Now lets take a look at the webHookHandler function.
The bot we are going to built reply's with a random joke when the user sends the command "/joke". For this we use a free API http://api.icndb.com/jokes/random.

Our WebHookHandler Function looks like this

func webHookHandler(rw http.ResponseWriter, req *http.Request) {

    // Create our web hook request body type instance
    body := &webHookReqBody{}

    // Decodes the incoming request into our cutom webhookreqbody type
    if err := json.NewDecoder(req.Body).Decode(body); err != nil {
        log.Printf("An error occured (webHookHandler)")
        log.Panic(err)
        return
    }

    // If the command /joke is recieved call the sendReply function
    if strings.ToLower(body.Message.Text) == "/joke" {
        err := sendReply(body.Message.Chat.ID)
        if err != nil {
            log.Panic(err)
            return
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

Whenever a message is received by the bot our http Server gets a request and we handle the request using this function.
You can see a webHookReqBody type which is a struct to which we decode the data received via http Request.

The webHookReqBody struct declaration :
We need to import the encoding/json package for this

type webHookReqBody struct {
    Message struct {
        Text string `json:"text"`
        Chat struct {
            ID int64 `json:"id"`
        } `json:"chat"`
    } `json:"message"`
}
Enter fullscreen mode Exit fullscreen mode

Now whenever our bot recieves a message an http request is recieved by our server and that http request body is decoded into the webHookHandler struct. Then we check if the message is "/joke" if it is then we call the sendReply Function :

func sendReply(chatID int64) error {
    fmt.Println("sendReply called")

    // calls the joke fetcher fucntion and gets a random joke from the API
    text, err := jokeFetcher()
    if err != nil {
        return err
    }

    //Creates an instance of our custom sendMessageReqBody Type
    reqBody := &sendMessageReqBody{
        ChatID: chatID,
        Text:   text,
    }

    // Convert our custom type into json format
    reqBytes, err := json.Marshal(reqBody)

    if err != nil {
        return err
    }

    // Make a request to send our message using the POST method to the telegram bot API
    resp, err := http.Post(
        "https://api.telegram.org/bot"+botToken+"/"+"sendMessage",
        "application/json",
        bytes.NewBuffer(reqBytes),
    )

    if err != nil {
        return err
    }

    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
        return errors.New("unexpected status" + resp.Status)
    }

    return err
}

Enter fullscreen mode Exit fullscreen mode

sendReply takes an argument the CHATID which is used to identify the telegram user inside the sendReply we first generate the text to be sent using the jokFetcher function which calls our API and gets a random joke for us.

func jokeFetcher() (string, error) {
    resp, err := http.Get("http://api.icndb.com/jokes/random")
    c := &joke{}
    if err != nil {
        return "", err
    }
    err = json.NewDecoder(resp.Body).Decode(c)
    return c.Value.Joke, err
}
Enter fullscreen mode Exit fullscreen mode

We have joke struct into which the joke gets decoded into

type joke struct {
    Value struct {
        Joke string `json:"joke"`
    } `json:"value"`
}
Enter fullscreen mode Exit fullscreen mode

In the senReply Function we have sendMessageReqBody struct whose declaration is as follows :

type sendMessageReqBody struct {
    ChatID int64  `json:"chat_id"`
    Text   string `json:"text"`
}
Enter fullscreen mode Exit fullscreen mode

Check out the full code here main.go

Now in order to test our bot you should first install ngrok on your system

then run

ngrok http 8080

Enter fullscreen mode Exit fullscreen mode

Now you will get a screen containing an https url copy that url and run the command

curl -F "url=YOUR_NGROK_URL_HERE" https://api.telegram.org/botYOUR_BOT_TOKEN_HERE/setWebhook
Enter fullscreen mode Exit fullscreen mode

Now run your main.go file then send your bot a message "/joke". Enjoy .!!!

Top comments (0)