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 thecmd_start
function.if the message contains the command
/help
, if so it calls thecmd_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 tokenDOMAIN
- the project URL (for examplehttps://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.