In this tutorial we will build a simple telegram bot using FastAPI which is a modern micro framework built with Python. main image

Table of contents

What

Telegram is widely used messaging platform that allows developers to build chat bots that can communicate with other users, manage channels, administer groups, and much more.

Python is a high-level, general-purpose programming language. It’s one of the best language for beginners as it’s known for the ability to write short, fast, and easy to read programs.

FastAPI is a high performance, easy to learn, fast to code, ready for production framework built on top of starlette and uses modern python features like asyncio, typing, and validation with Pydantic.

Here’s a basic example of a FastAPI application:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World"}

In this tutorial we will build a simple telegram bot using FastAPI.

The bot is very simple, it takes a message from the user containing a phone number and replies with a message containing a whatsapp link to a direct chat with that phone number.

Steps

Create a new bot with Botfather.

Open a chat with @BotFather. then Hit Start.

Create a new bot using the command /newbot, then send the bot a message with the name of the bot you want to create.

After that, it will ask you for a username of your bot, notice that the username must end with bot for example mybotbot.

Then, it will ask you for a description of your bot.

Once the username is chosen, your bot will be automatically created and ready to use.

Please note: The API token is the key for your bot to communicate with the Telegram system. IT MUST BE KEPT SAFE! Do not use that token for anything other than the bot you’ll create.

Create a new Python project

Clone this repo using the command:

git clone https://github.com/amr3k/oiwa.git
cd oiwa

Environment Setup

Create a new virtual environment

Notice you’ll need to install the virtualenv package.

virtualenv -p python3 oiwa

Install the dependencies with the following command:

pip install -r requirements.txt

This will install the required dependencies for your project.

Environment variables

In the main.py file, you’ll notice that it includes the following code.

DOMAIN = environ.get("DOMAIN")
BOT_TOKEN = environ.get("BOT_TOKEN")

Those are called environment variables which you’ll set later on when we reach the deployment step.

Coding time

In our case we need the following endpoints:

  • /setwebhook to set the webhook which will be used to receive updates from Telegram.
  • /telegram-update to receive updates from Telegram.

So we’ll need to visit /setwebhook and set the webhook to the URL https://<your-domain>/update.

This is required only once after deploying the application.

Importing modules

We need to import those modules first.

from fastapi import FastAPI
from fastapi.responses import HTMLResponse

from telegram.bot import Bot

Bot object

Now we can create our Telegram bot object.

bot = Bot(BOT_TOKEN)

This bot object is used to communicate with the Telegram API using built in methods.

Now we initiate the FastAPI application object:

app = FastAPI()

Adding main functions

Now lets add the first function:

@app.get("/setwebhook")
async def set_webhook():
    s = bot.set_webhook(url=f"{DOMAIN}/telegram-update")
    if s:
        return HTMLResponse("ok")
    else:
        return HTMLResponse("Error!")

We need to add the webhook handler which receives raw telegram update in a json form and calls the update handler function we’ll add later.

But before this, we’ll need to import the following modules:

from fastapi.requests import Request
from telegram.update import Update
@app.post("/telegram-update")
async def webhook_handler(request: Request):
    data = await request.json()
    upcoming_update = Update.de_json(data, bot=bot)
    await update_handler(upcoming_update)
    return "ok"

Notice it receives a POST request

Now lets add the update handler function which receives updates from Telegram.

Again, we’ll need to import the following modules first:

from telegram.chataction import ChatAction
from telegram.error import Unauthorized
async def update_handler(update: Update):
    try:
        if update.effective_message.text:
            bot.send_chat_action(
                chat_id=update.effective_chat.id, action=ChatAction.TYPING
            )
            if update.effective_message.text == "/start":
                await cmd_start(update=update)
            elif update.effective_message.text == "/help":
                await cmd_help(update=update)
            elif re.fullmatch("+[0-9s?-?]{5,20}", update.effective_message.text):
                await phone_handler(update=update)
            else:
                await wrong_number(update=update)
        else:
            cmd_help(update=update)
    except (Unauthorized, AttributeError):
        pass

So this function will receive updates from Telegram and matches the message pattern to call the appropriate helper function.

First , it sends a typing action to telegram so the user will see the bot is Typing.

Then it does the following checks:

  • if the message contains the command /start, if so it calls the cmd_start function.

  • if the message contains the command /help, if so it calls the cmd_help function.

  • if the message contains a phone number (using regular expressions), if so it calls the phone_handler function.

Adding the helper functions

In order to be able to use Markdown formatting code in the bot responses, we need to import the ParseMode from the telegram.parsemode package.

from telegram.parsemode import ParseMode

Start command handler

async def cmd_start(update: Update):
    bot.send_message(
        chat_id=update.effective_chat.id,
        text=f"Hello {update.effective_user.full_name} 👋🏻\nPlease send a phone number you want to chat with including international code",
        parse_mode=ParseMode.MARKDOWN_V2,
    )

Help command handler

async def cmd_help(update: Update):
    bot.send_message(
        chat_id=update.effective_chat.id,
        text="You can send the phone number you want to chat with **including international code** (eg +447419651046)",
        parse_mode=ParseMode.MARKDOWN_V2,
    )

It’s also recommended to add this function to respond in case the user sent a wrong message.

async def wrong_number(update: Update):
    bot.send_message(
        chat_id=update.effective_chat.id,
        text="❌ Wrong number",
        parse_mode=ParseMode.MARKDOWN_V2,
    )

Finally, we need to add the phone number handler, but for it we’ll need to import the inline keyboard modules.

from telegram.inline.inlinekeyboardbutton import InlineKeyboardButton
from telegram.inline.inlinekeyboardmarkup import InlineKeyboardMarkup

The phone handler function should be like this.

async def phone_handler(update: Update):
    bot.send_message(
        text="ok",
        chat_id=update.effective_chat.id,
        reply_markup=InlineKeyboardMarkup(
            [
                [
                    InlineKeyboardButton(
                        text="🔗 Open chat",
                        url=f"https://api.whatsapp.com/send?phone={update.effective_message.text.replace(' ','').replace('-','')}",
                    )
                ]
            ]
        ),
    )

You could use regular expressions to remove whitespaces and dashes from the phone number.

There’s also an optional function to tell web crawlers not to index the page.

@app.get("/robots.txt")
async def robots():
    return HTMLResponse("User-agent: *\nDisallow: /")

Deployment

I chose Vercel for deployment.

You need to create your own account, then install the Vercel CLI.

In the project directory, run the following command:

vc

Then you can deploy your project to Vercel.

vc --production

Now open your account in the browser and go to the project page.

Open the projcet settings and look for Environment Variables tab.

Add the following environment variables:

  • BOT_TOKEN - your bot token
  • DOMAIN - the project URL (for example https://my-project.vercel.app)

Now visit your project URL to invoke the setwebhook function. (for example https://my-project.vercel.app/setwebhook)

Test your bot

Open telegram, look for your bot username, start it and send a message containing a phone number.

Conclusion

In this tutorial, we learned how to create a fast and simple telegram bot using FastAPI and Python Telegram bot library.

The source code of the whole project lives at my github repo

If you find this tutorial helpful, please star my repo, and feel free to share this article with your friends.

Related topics