Build a Telegram Bot to Send Notifications in Node.js with TypeScript
Instead of using Telegram bot frameworks like telegraf.js and node-telegram-bot-api, I created a Telegram sender with less than 100 lines of code in Node.js to simply send notifications to myself. And there is nothing wrong with using a full-featured framework, but building your own is definitely easier to maintenance.
Build Your Own Telegram Bot
Follow this section to wrote your own Telegram bot in TypeScript, or to use the library directly.
Create Bot
First thing first, create a bot API key with @BotFather on Telegram:
Import https
module
Import the https
module from Node.js:
import https from 'https';
TypeScript
Add Type Declarations
If your IDE shows the error Cannot find module 'https' or its corresponding type declarations.
, install the typings of Node.js would resolve this error:
$ npm i -D @types/node
Ignore this part if not using TypeScript.
Parse Modes
Define message parse modes from the official documentation:
enum Telegram_ParseModes {
MarkdownV2,
HTML,
}
TypeScript
Main Code
We'll be creating a class
for the module, so different bot instances could be created at runtime:
class Telegram {
private readonly api: string;
constructor(api: string) {
// store the API key
this.api = api;
}
}
TypeScript
Then a private
method to help us make the requests:
class Telegram {
...
private request<T extends Record<string, any>>(path: string, data?: Record<string, any>): Promise<{ ok: boolean; } & Partial<T>> {
return new Promise((resolve, reject) => {
const req = https.request('https://api.telegram.org/bot' + this.api + path, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
}, (res) => {
let result = '';
res
.setEncoding('utf-8')
.on('data', (chunk) => {
result += chunk;
})
.on('end', () => {
resolve(JSON.parse(result));
});
}).on('error', reject);
if (data) {
req.write(JSON.stringify(data));
}
req.end();
});
}
}
TypeScript
Create a public
method for sending message:
class Telegram {
...
public async send(id: number | string, text: string, parseMode?: Telegram_ParseModes): Promise<boolean> {
return (await this.request('/sendMessage', {
chat_id: id,
text: text,
parse_mode: parseMode === undefined ? undefined : Telegram_ParseModes[parseMode],
})).ok;
}
}
TypeScript
Get Your Own ID
Since we're gonna send notifications to ourselves, let's write a helper to get our own Telegram ID:
class Telegram {
...
private updates?: number;
...
public async findID(): Promise<Record<string, number>> {
const updates = await this.request<{
result: {
update_id: number;
message: {
from: {
id: number;
is_bot: boolean;
username: string;
};
};
}[];
}>('/getUpdates', this.updates === undefined ? undefined : { offset: this.updates });
const users: Record<string, number> = {};
const result = updates.result;
if (result) {
const resultLength = result.length;
for (let i = 0; i < resultLength; i++) {
const item = result[i];
if (!item.message.from.is_bot) {
users[item.message.from.username] = item.message.from.id;
}
}
this.updates = result[resultLength - 1].update_id + 1;
}
return users;
}
}
TypeScript
Usage
Find out our ID (remember to send something to your bot first):
const telegram = new Telegram('api_key');
telegram.findID().then((users) => {
console.log(users);
});
TypeScript
{ Username: 1234567890 }
Output
Send message to 1234567890
with the MarkdownV2
parse mode:
telegram.send(1234567890, '*Hello World\\!*', Telegram_ParseModes.MarkdownV2);
TypeScript
Full Example
Module
telegram.tsimport https from 'https';
export enum Telegram_ParseModes {
MarkdownV2,
HTML,
}
export default class Telegram {
private readonly api: string;
private updates?: number;
constructor(api: string) {
this.api = api;
}
public async send(id: number | string, text: string, parseMode?: Telegram_ParseModes): Promise<boolean> {
return (await this.request('/sendMessage', {
chat_id: id,
text: text,
parse_mode: parseMode === undefined ? undefined : Telegram_ParseModes[parseMode],
})).ok;
}
public async findID(): Promise<Record<string, number>> {
const updates = await this.request<{
result: {
update_id: number;
message: {
from: {
id: number;
is_bot: boolean;
username: string;
};
};
}[];
}>('/getUpdates', this.updates === undefined ? undefined : { offset: this.updates });
const users: Record<string, number> = {};
const result = updates.result;
if (result) {
const resultLength = result.length;
for (let i = 0; i < resultLength; i++) {
const item = result[i];
if (!item.message.from.is_bot) {
users[item.message.from.username] = item.message.from.id;
}
}
this.updates = result[resultLength - 1].update_id + 1;
}
return users;
}
private request<T extends Record<string, any>>(path: string, data?: Record<string, any>): Promise<{ ok: boolean; } & Partial<T>> {
return new Promise((resolve, reject) => {
const req = https.request('https://api.telegram.org/bot' + this.api + path, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
}, (res) => {
let result = '';
res
.setEncoding('utf-8')
.on('data', (chunk) => {
result += chunk;
})
.on('end', () => {
resolve(JSON.parse(result));
});
}).on('error', reject);
if (data) {
req.write(JSON.stringify(data));
}
req.end();
});
}
}
TypeScript
App
index.tsimport Telegram, { Telegram_ParseModes } from './telegram';
const telegram = new Telegram('api_key');
telegram.send('chat_id', '*Hello World\\!*', Telegram_ParseModes.MarkdownV2);
TypeScript
Use Directly
To use the telegram sender without building your own, install tele-sender
from npm:
$ npm i tele-sender
Then import tele-sender
and it's ready to use:
import Telegram, { Telegram_ParseModes } from 'tele-sender';
const telegram = new Telegram('api_key');
telegram.send('chat_id', '*Hello World\\!*', Telegram_ParseModes.MarkdownV2);
TypeScript