Build a Telegram Bot to Send Notifications in Node.js with Typescript

mail
Cyrus Kao
Last modified

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:

BotFather
BotFather on Telegram

Import https module

Import https module from Node.js:

import https from 'https';
TypeScript

Add Type Declarations

If 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
Bash

Ignore this part if not using Typescript.

Define Parse Modes

Define message parse modes from the official documentation:

enum Telegram_ParseModes {
	MarkdownV2,
	HTML,
}
TypeScript

Create Class

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 the 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

Helper to 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 MarkdownV2 parse mode:

telegram.send(1234567890, '*Hello World\\!*', Telegram_ParseModes.MarkdownV2);
TypeScript

Full Example

  • Module telegram.ts
import 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.ts
import 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
Bash

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

Comments

0500