NoCache

Table of Contents

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

Cyrus Kao
Last modified on .

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

Comments

Sign in to leave a comment.