Telegram Bot on Netlify Functions

April 7, 2018

Today i am gonna show you how you can build a simple Telegram echo bot using golang and Netlify Functions.

If you wanna jump right into the code here is the Github repo.

Before we begin make sure you have the following

  1. Golang
  2. Git
  3. Github, Gitlab or Bitbucket account
  4. Netlify Account

Here is what we’re gonna do

  1. Setup a simple static site
  2. Write the backend for the bot using golang
  3. Configure a simple build system
  4. Deploy site and function to netlify
  5. Connect the backend to the Telegram Bot

1. Setup simple static site

Then we create a simple html file to serve as the index of our site

site/index.html

<html>
  <head>
    <title>Telegram Echo Bot Using Netlify Functions</title>
  </head>
  <body>
    <h1>A Telegram Echo Bot Using Netlify Functions</h1>
    <p>This is a simple telegram echo bot built using golang and Netlify Functions.</p>
  </body>
</html>

Now that we have our html file we will start coding our backend for our bot.

2. Write Bot Backend In Go

It’s beyond the scope of this article to teach you go so check the go tour if you need a refresher

main.go

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strings"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
)

var TELEGRAM_BOT_TOKEN string

type Data struct {
	UpdateID int `json:"update_id"`
	Message  struct {
		MessageID int `json:"message_id"`
		From      struct {
			ID           int    `json:"id"`
			IsBot        bool   `json:"is_bot"`
			FirstName    string `json:"first_name"`
			Username     string `json:"username"`
			LanguageCode string `json:"language_code"`
		} `json:"from"`
		Chat struct {
			ID        int    `json:"id"`
			FirstName string `json:"first_name"`
			Username  string `json:"username"`
			Type      string `json:"type"`
		} `json:"chat"`
		Date int    `json:"date"`
		Text string `json:"text"`
	} `json:"message"`
}

func handler(req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {

	if req.HTTPMethod != "POST" {
		return events.APIGatewayProxyResponse{
			StatusCode: 204,
            Body:       "Hello There..."
		}, nil
	}

	var err error

	data := Data{}

	if err = json.Unmarshal([]byte(req.Body), &data); err != nil {

		log.Println(err)

		return events.APIGatewayProxyResponse{
			StatusCode: 503,
		}, nil

	}

	if strings.Contains(data.Message.Text, "start") {
		return events.APIGatewayProxyResponse{
			StatusCode: 204,
		}, nil
	}

	responseData := map[string]interface{}{
		"text":    data.Message.Text,
		"chat_id": data.Message.Chat.ID,
	}

	var responseDataJSON []byte

	if responseDataJSON, err = json.Marshal(responseData); err != nil {

		log.Println(err)

		return events.APIGatewayProxyResponse{
			StatusCode: 503,
		}, nil

	}

	if request, err := http.NewRequest("POST", fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", TELEGRAM_BOT_TOKEN), bytes.NewReader(responseDataJSON)); err != nil {

		log.Println(err)

		return events.APIGatewayProxyResponse{
			StatusCode: 503,
		}, nil

	} else {

		request.Header.Set("Content-Type", "application/json")

		client := &http.Client{}

		if _, err = client.Do(request); err != nil {

			log.Println(err)

			return events.APIGatewayProxyResponse{
				StatusCode: 503,
			}, nil

		}

	}

	return events.APIGatewayProxyResponse{
		StatusCode: 204,
	}, nil

}

func main() {
	lambda.Start(handler)
}

3. Configure a simple build system

Then we configure our build sytem and environment settings

netlify.toml

[build]
  command = "make build"
  functions = "functions"
  publish = "site"
[build.environment]
  # Change this path with the path to your repository
  GO_IMPORT_PATH = "github.com/zolamk/telegram-echo-bot"

here we have a simple netlify confiuration file that specifies build command, functions location, publish location and go import path.

Makefile

build:
	mkdir -p functions
	go get ./...
	go build -ldflags "-X main.TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}" -o functions/echo ./...

Then we create a Makefile for our build command the only thing special about our make file is on line 4 we use linker flags to set variable defined in our code at build time.

4. Deploy to netlify

  • Commit and push your git repo
  • Create a new netlify site using your git repo

If all goes well you should see Hello There... when you access <your netlify site url>/.netlify/functions/echo

5. Connect the backend to the telegram bot

Our bot and backend are connected using webhooks so we need to set a webhook on our bot, we can call the Telegram Bot API using curl for that

curl --request POST --url https://api.telegram.org/bot<TELEGRAM BOT TOKEN>/setWebhook --header 'content-type: application/json' --data '{"url": "<NETLIFY SITE URL>/.netlify/functions/echo"}'

If all goes well you will get the following message

{"ok": true,"result": true,"description": "Webhook was set"}