Building a Telegram Bot with Azure Functions and Node.js
Tags: azure, telegram, bot, node
Published: 2020-07-14 06:34:12

Introduction
------------

In this tutorial, we will create an Azure Function with a simple Telegram Bot (Echo Bot). We will test it locally and then deploy it to Azure Portal. It means our bot will work only at the moment when someone is using it. So the function will be triggered only when someone is sending a message to a bot.

Flow Review
-----------

1.  The user sends any message to Telegram Bot
2.  Telegram sends requests via Webhook to our Azure Function
3.  Azure Function replies to Webhook with a copied message

Prerequisites
-------------

-   node.js - v10.16.2
-   npm - v6.14.5
-   telegraf - v3.38.0
-   ngrok - v2.3.35
-   Azure subscribtion
-   you need to install [Azure Functions extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions) to Visual Studio Code

Create an Azure function in Visual Studio Code
----------------------------------------------

1.  click on Azure Icon in Visual Studio Code:![Azure Icon in VSC](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-07-at-10.48.39-1024x885.png)
2.  login under your Azure subscription
3.  click on "Create Function Icon":![Create Function Icon](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-07-at-10.51.16.png)
4.  you will be asked to use an existing project or create a new. Let's create a new:![Create a new project](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-07-at-10.54.40-1024x281.png)![Create new project folder](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-07-at-10.55.13-1024x589.png)
5.  select the function template. We will use **HTTP trigger**:![Choose a Function Template](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-07-at-10.55.36-1024x607.png) 
6.  provide a function name and select Enter:![Enter the name of the function](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-07-at-10.56.16-1024x213.png)
7.  please provide a **Function** key for a **Function authorization**:![Function Authorization level](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-07-at-10.56.27-1024x280.png)
8.  penultimate step. Select how you would like to open a project. We will use the current window:![How to open a function project in Visual Studio Code](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-07-at-10.56.39-1024x291.png)
9.  you will be redirected to the **default HTTP trigger function with Javascript code**:![The default function Code](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-07-at-10.57.02-1024x618.png)
10. now this function will appear in Azure Functions section:
![Newly created function](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-07-at-11.23.30-1024x340.png)

Folder structure
----------------

![Function Folder Structure](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-07-at-11.29.34-300x256.png)

-   **package.json** - metadata relevant to the Node.js project
-   **proxies.json** - you can modify requests and responses from function
-   **host.json** - metadata file relevant to the Azure project. It's a global configuration for all functions in an application
-   **azure-bot-cloud-function** - it's our function folder. Each function has a separate folder with code file (.js in our case) and function.json. Function.json it's a [binding configuration file](https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-expressions-patterns).

Run function locally
--------------------

1.  Select "Run" -> "Start Debugging" in Visual Studio Code menu
2.  If you have no Azure Functions Core Tools locally, you need to install them on this step. The instruction can be found in [Azure repo:](https://github.com/Azure/azure-functions-core-tools#installing)![Install Azure Function Core Tools](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-07-at-20.48.48-1024x127.png)
3.  You should see how the NPM tasks will executing and finally get a link to the working function:![Link to the local Azure function](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-07-at-21.08.28-1024x601.png)
4.  Let's open our function in the browser:![Azure Function is working locally](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-07-at-21.20.46-1024x274.png)

    As you see, the function responds to us with the behavior by default. Also, you can simply run the function using the **func start** command.

Implement the bot
-----------------

For work with Telegram API, we will use the most popular library for Node.js - [Telegraf.js](https://github.com/telegraf/telegraf). We need to install it in the project folder:
```bash
npm install telegraf --save
```
Please make sure the `package.json` has Telegraf after the running previous command.

Because Telegram will send webhook requests to our bot, we need to make an external HTTPS URL. For this purpose we can use [ngrok library](https://ngrok.com/):
```bash
npm install ngrok -g
```
If all is good, we can go to `<function-folder>/index.js` and create a simple Echo-bot:
```javascript
const Telegraf = require('telegraf')
const { TELEGRAM_BOT_TOKEN, WEBHOOK_ADDRESS } = process.env

const bot = new Telegraf(TELEGRAM_BOT_TOKEN, {
    telegram: { webhookReply: true }
})

bot.telegram.setWebhook(WEBHOOK_ADDRESS)
bot.on('message', (ctx) => ctx.telegram.sendCopy(ctx.chat.id, ctx.message))

module.exports = async function(context, req) {
    return bot.handleUpdate(req.body, context.res)
}
```
You can take `TELEGRAM_BOT_TOKEN` value from [BotFather bot](https://telegram.me/BotFather). The `WEBHOOK_ADDRESS` will contain a link to the Azure Function. We will talk about this variable later.
Our bot will work in Webhook mode - it's a more preferable way to run Telegram bot. The Telegram will automatically inform our bot about all updates. In the polling mechanism, our bot needs to frequently ask Telegram about updates, so it requires non-stop work for our bot (most cases).

Running bot locally
-------------------

To run this bot locally we need to create a public address using `ngrok`. By default, the local Azure function is running on port `7071`. We can use the following combination in the terminal to create a public URL:
```bash
ngrok http 7071
```
In the terminal you will get your HTTPS link for testing Webhook:

![HTTPS public URL using ngrok](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-13-at-22.29.42-1024x400.png)

Copy the ngrok-created link and add the route to the function. Something similar to this:
```javascript
bot.telegram.setWebhook('https://<random-value>.ngrok.io/api/azure-bot-cloud-function')
```
Also, don't forget to pass a real Telegram token to the Telegraf constructor:
```javascript
const bot = new Telegraf('some-token-value', {
	telegram: { webhookReply: true }
})
```
It's very dirty, but for a quick test it's OK, so please remember to remove all real keys from the code.

Then you can run a function just using the simple command:
```bash
func start
```
![Azure Functions is running locally](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-13-at-22.49.14-1024x709.png)

Good job! Now open your bot in Telegram and send any message. Our bot should copy it and resend to you:

![Echo-Bot example](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-13-at-23.41.16.png)

Deploy Azure Function to the portal
-----------------------------------

To deploy Azure Function we just need to click on this button:

![Deploy Azure Function](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-13-at-22.52.40-1024x730.png)

Then choose your resource and press "Deploy". The process will be started:

![The process of deploying Azure Function](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-13-at-22.53.55-1024x406.png)

After successful deployment, we need to go to Azure Portal and update `WEBHOOK_ADDRESS` and `TELEGRAM_BOT_TOKEN` variables with real values.

To get a real function URL, go to "Functions", then choose your Azure Function and press "Get Function Url" button:

![How to get Azure Function URL](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-13-at-23.05.24-1024x275.png)

We need to copy this value and paste to "Application Settings" along with Telegram Token:

![Application Settings in Azure](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-13-at-22.59.12-1024x343.png)

After adding our secret keys, press "Save" and restart our application:

![Restart Azure application](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-13-at-23.09.41-1024x424.png)

That's all. Our bot should work in the cloud and you can track all function executions in real-time:

![Azure Dashboard](http://akhromieiev.com/wp-content/uploads/2020/07/Screenshot-2020-07-13-at-23.13.07-1024x325.png)

Each function execution means that our bot handled 1 single message.

Conclusion
----------

In this tutorial, we have created an Azure Function with a simple Echo-Bot for Telegram. Azure Functions its a cool way to host your bots. You will be chargeable by the simple formula - (Memory size)X(Execution time in ms)X(Executions per month) and also remember that the first 400,000 GB/s of execution and 1,000,000 executions are free. If you need to estimate your pricing costs you can use [this pricing calculator](https://azure.microsoft.com/en-us/pricing/calculator/).