Telegram Bot With Node.js in 30 Lines Of Code

Photo by h heyerlein on Unsplash

Hi everyone. Bots are useful sometimes (and sometimes they aren’t). Here I’d like to demystify one of the shortest examples of the bot which does something (a little bit more than “hello world”). Also, I’d keep the text concise but informative.
If you are an experienced developer or a beginner — it’s going to be easy for you. Repo with working code is provided at the end of the article.
There are two ways, how to create a bot. You can initially write it for some specific problem or dig deeper and make it platform agnostic.
The first option is much more accessible for the demo purposes so that we will proceed with it.

We’re not going to waste time to implement something, which is already implemented and works great.
I suggest using ‘node-telegram-bot-API ‘ library for interaction with telegram server and ‘request’ for XHR.

We have to solve some problem with our bot. I’ve decided to deliver the plans of spaceships launches to the user. There are not so many of them to avoid implementation of filters and pagination. By design, it should make a single request, parse data and deliver it to the user. I investigated some open API’s and found following: https://launchlibrary.net/1.3/launch . It is a perfect candidate: it returns JSON, doesn’t require any authorization and does everything with a single request. We are ready to run into space.

Photo by Juskteez Vu on Unsplash

You need register your bot first and obtain a token. It can be done quite quickly, just add ‘@BotFather’ bot, start the conversation and follow the instructions. It’s going to take a couple of minutes, is quite simple and… well, it’s explained much time on the internet, so I’d like to avoid doing a “rewriting.” That’s it; you are ready for coding.

I’ll keep it as simple as possible. Technically, the whole example can be written in one single file. It’s a bad practice for real projects, but quite good for demonstration purposes. But we need a node.js project to use libraries, so create a folder and initiate npm there (npm init). Create an .js in there.

We will need following dependencies:

node-telegram-bot-api
request

We need to install them.

Afterwards, let’s declare our dependencies in code:

const Bot = require('node-telegram-bot-api');
const request = require('request');

Also, let’s add some constants we need to our app:

const url = 'https://launchlibrary.net/1.3/launch';
const trigger = 'I want to travel!';
const token = 'PLACE_YOUR_TOKEN_HERE';

url is the API with schedule of space launches

trigger is a string, which we expect from user in order to send him data

token is a string, which we expect from the user in order to send him data

Now we are ready to create a bot. It’s important to mention that you can interact with a server in two ways:

Webhooks — technically is just a regular HTTP communication

Long Polling — quite old technology which has lost its popularity on the web, but is helpful in our case. It allows running application (chatbot) locally without any dedicated server and available external address. So we will proceed with it.

Different platforms (i.e., facebook, slack, etc.) provide different ways how to interact with their servers, but summarising there are three options: Webhooks, Websockets, and Long Polling. Every method has its pros/cons. It’s quite significant and debatable topic which I will not cover in this post. Just ping me somehow if you’re interested in that.

So let’s create our bot with long polling configuration:

const Bot = require('node-telegram-bot-api');
const request = require('request');
const token = 'token';
const url = 'https://launchlibrary.net/1.3/launch';
const trigger = 'I want to travel!';
const bot = new Bot(token, {polling: true});

What drives bot? Events. When the user types a message — we get an event. So let’s subscribe to the event and get the message:

bot.on('message', (event) => console.log(event.text.toString());

So, great, we finally got something from our user! :) When the user adds a bot he always sends a ‘/start’ message. It’s a good practice to respond with some “help” information — list of commands and description for them. Also, many platforms, including telegram, provide you a possibility to send predefined answers, buttons, which user can select without typing, which are very and very helpful. So let’s give a default answer to our user:

bot.on('message', (msg) => {
bot.sendMessage(msg.chat.id, 'Hi, do you want to travel?', {
reply_markup: {
keyboard: [[trigger], ['Bulk option']]
}
});
});

I hope the code is self-documenting here, but we have a bot object which provides us an event listener and API either. We send a response with text and predefined buttons, which are passed as an object for “reply_markup.”

trigger —is a variable with a string we expect to get from the user, so we provide him a button with it.

Tip: It makes sense to use emojis in answers. Chatbots are similar to console line interfaces partially, and the user can be bored because of lots of text. Emojis are one of the available options for visualization. It’s not “childish,” many bots do so.

Now our bot responds by default message for every message. Let’s add an exclusion for target string and do some logic what we really wanted to:

bot.on('message', (msg) => {
if (msg.text.toString() === trigger) {
return request(url, (err, resp, body) => {
bot.sendMessage(msg.chat.id, prepareData(body));
});
}
bot.sendMessage(msg.chat.id, 'Hi, do you want to travel?', {
reply_markup: {
keyboard: [[trigger], ['Bulk option']]
}
});
});

Looks easy, huh? When we got a target string — we just make a GET request to a server, parse data and give it to our user. Function for data parsing is small either:

const prepareData = (body) => {
const launches = JSON.parse(body).launches;
return launches.filter((launch) => launch !== undefined)
.map((launch) => `${launch.name} on ${launch.net}`)
.join('\n\n');
};

We just filter empty items, map object keys into the string and adding a newline symbols between entries.

DO NOT handle user input and API responses in such way in real apps. The example is simplified, and in real life, some validations and exception handling is a MUST.

You can see the whole application here:

const Bot = require('node-telegram-bot-api');
const request = require('request');
const token = require('./token');
const url = 'https://launchlibrary.net/1.3/launch';
const trigger = 'I want to travel!';
const bot = new Bot(token, {polling: true});const prepareData = (body) => {
const launches = JSON.parse(body).launches;
return launches.filter((launch) => launch !== undefined)
.map((launch) => `${launch.name} on ${launch.net}`)
.join('\n\n');
};
bot.on('message', (msg) => {
if (msg.text.toString() === trigger) {
return request(url, (err, resp, body) => {
bot.sendMessage(msg.chat.id, prepareData(body));
});
}
bot.sendMessage(msg.chat.id, 'Hi, do you want to travel?', {
reply_markup: {
keyboard: [[trigger], ['Bulk option']]
}
}
);
});

You can check the repo with code. It’s ready to use and waits for your experiments https://github.com/tryshchenko/30-lines-telegram-bot

I hosted the example on the telegram, just add @tospace_bot. It’s hosted on quite cheap VPS, and I hope it will survive :) Also you can check how does it work on this gif.

Thanks for reading! It’s my first article here; please point out to me if I’ve done something wrong.

Chatbots Magazine

Chatbots, AI, NLP, Facebook Messenger, Slack, Telegram, and…