DEV Community

Castanderness
Castanderness

Posted on

5 Telegram Bot Patterns Every Python Developer Should Know

5 Telegram Bot Patterns Every Python Developer Should Know

After building 50+ bots, these patterns solve 90% of problems.

1. FSM for Multi-Step Flows

from aiogram.fsm.state import State, StatesGroup

class OrderFlow(StatesGroup):
    product = State()
    quantity = State()
    address = State()

@dp.message(Command('order'))
async def start_order(message: Message, state: FSMContext):
    await state.set_state(OrderFlow.product)
    await message.answer('What product?')

@dp.message(OrderFlow.product)
async def get_product(message: Message, state: FSMContext):
    await state.update_data(product=message.text)
    await state.set_state(OrderFlow.quantity)
    await message.answer('How many?')
Enter fullscreen mode Exit fullscreen mode

2. Throttle Decorator

from functools import wraps
import time

_last_call = {}

def throttle(rate_limit: int = 3):
    def decorator(func):
        @wraps(func)
        async def wrapper(message: Message, *args, **kwargs):
            uid = message.from_user.id
            now = time.time()
            if now - _last_call.get(uid, 0) < rate_limit:
                await message.answer('Please wait...')
                return
            _last_call[uid] = now
            return await func(message, *args, **kwargs)
        return wrapper
    return decorator
Enter fullscreen mode Exit fullscreen mode

3. Paginated Results

def paginate(items: list, page: int, per_page: int = 5):
    start = page * per_page
    return items[start:start + per_page], len(items) // per_page

def build_page_kb(page: int, total: int) -> InlineKeyboardMarkup:
    btns = []
    if page > 0:
        btns.append(InlineKeyboardButton('Prev', callback_data=f'page:{page-1}'))
    if page < total:
        btns.append(InlineKeyboardButton('Next', callback_data=f'page:{page+1}'))
    return InlineKeyboardMarkup(inline_keyboard=[btns])
Enter fullscreen mode Exit fullscreen mode

4. Admin Middleware

from aiogram import BaseMiddleware

class AdminMiddleware(BaseMiddleware):
    def __init__(self, admin_ids: list[int]):
        self.admin_ids = admin_ids

    async def __call__(self, handler, event, data):
        user = data['event_from_user']
        if user.id not in self.admin_ids:
            await event.answer('Admin only')
            return
        return await handler(event, data)

dp.message.middleware(AdminMiddleware([ADMIN_ID]))
Enter fullscreen mode Exit fullscreen mode

5. Retry on Network Errors

async def safe_send(bot: Bot, chat_id: int, text: str, retries: int = 3):
    for attempt in range(retries):
        try:
            return await bot.send_message(chat_id, text)
        except TelegramRetryAfter as e:
            await asyncio.sleep(e.retry_after)
        except TelegramForbiddenError:
            db.mark_inactive(chat_id)
            return None
        except Exception:
            if attempt == retries - 1:
                raise
            await asyncio.sleep(2 ** attempt)
Enter fullscreen mode Exit fullscreen mode

Need a production-ready bot with these patterns? Find me on Upwork.

From $49 | 2-3 days | Full source code included

Top comments (0)