5.14-bob: Telegram bot — node-telegram-bot-api va Telegraf
5-QISM — Node.js Backend · 14-mavzu
1. Kirish va motivatsiya
Real-time aloqani 5.13-bob bildik. Endi O'zbekistonda juda keng tarqalgan, amaliy va daromadli mavzuni — Telegram bot yaratishni — o'rganamiz. O'zbekistonda Telegram — eng ommabop ilova; deyarli har bir biznes (do'kon, restoran, klinika, taksi, ta'lim markazi) Telegram bot orqali ishlaydi: buyurtma qabul qilish, ro'yxatga olish, bildirishnoma yuborish, mijozlar bilan aloqa. Bot yozishni bilgan backend dasturchi — bozorda juda talab qilinadi (freelance va ish o'rni uchun).
Bot — bu Telegram ichida ishlaydigan avtomatik dastur. U foydalanuvchi xabarlariga javob beradi, tugmalar ko'rsatadi, ma'lumot so'raydi, to'lov qabul qiladi — hammasi sizning Node.js kodingda boshqariladi. Texnik jihatdan bot — bu sizning serveringdagi 5.5-bob dastur, u Telegram Bot API (Telegram serveri bilan gaplashadigan interfeys) orqali xabarlarni oladi va yuboradi.
Bu bob — aslida hozirgacha o'rgangan hamma narsaning (server, event, async, DB, validatsiya — 5.1–5.13) amaliy birlashmasi. Bot — backend mantig'ining Telegram'dagi "yuzi".
O'xshatish: Telegram bot — restorandagi avtomatik ofitsiant. Mijoz kirib keladi (
/start), ofitsiant menyu beradi (tugmalar/klaviatura), mijoz tanlaydi (tugma bosadi callback), ofitsiant buyurtmani oshxonaga (sizning serveringga, DB'ga — 6) yuboradi, tayyor bo'lganda xabar beradi (bildirishnoma). Ofitsiantning "miyasi" — sizning Node.js kodingiz; Telegram — faqat zal (interfeys). Ofitsiant qanday gaplashishi, nimani so'rashi — hammasi kodda.
Nega muhim?
- O'zbekiston bozori — Telegram bot biznes uchun standart; juda ko'p talab.
- Amaliy birlashma — server, async, DB, validatsiya, SMS 5.18-bob — hammasi botda.
- Stack talabi — Najot Ta'lim va sizning stack'ingda bor (NestJS Telegraf — 8.20 bilan ham).
- Tez natija — kam kod bilan ishlaydigan mahsulot; portfel uchun a'lo.
2. Nazariya — chuqur tushuntirish
2.1. Bot qanday ishlaydi (umumiy rasm)
Bot — to'g'ridan Telegram serveriga ulanmaydi foydalanuvchi bilan. O'rtada Telegram Bot API turadi:
Foydalanuvchi ──xabar──▶ Telegram serveri ──update──▶ Sizning botingiz (Node.js)
Foydalanuvchi ◀──javob── Telegram serveri ◀──API──── Sizning botingiz
Siz Telegram serveriga gapirasiz (Bot API), u foydalanuvchiga yetkazadi.
Foydalanuvchini to'g'ridan ko'rmaysiz — Telegram orqali.Demak: sizning botingiz — oddiy Node.js dastur 5.1-bob. U Telegram serveridan update (yangilanish — yangi xabar, tugma bosilishi) oladi, qayta ishlaydi, va Bot API orqali javob yuboradi.
2.2. BotFather va token
Bot yaratish Telegram'dagi @BotFather (botlarning "otasi" — rasmiy bot) orqali:
1. Telegram'da @BotFather'ni oching
2. /newbot buyrug'ini yuboring
3. Botga nom va username bering (username "bot" bilan tugashi shart: mydo'kon_bot)
4. BotFather TOKEN beradi: 123456789:AbCdefGhIJKlmNoPQRsTUVwxyZToken — bot paroli (14): kim token'ga ega bo'lsa, botni to'liq boshqaradi. Uni hech qachon kodga yozmang/git'ga qo'ymang 4.5-bob —
.envda saqlang 5.8-bob. Token sizib chiqsa — BotFather'da/revokebilan yangisini oling.
2.3. Update'ni qabul qilish: Polling vs Webhook
Bot Telegram'dan update'ni ikki usul bilan oladi (grammy/hostman):
1. LONG POLLING — bot Telegram'dan "yangi xabar bormi?" deb DOIM so'raydi
Foydalanuvchi Telegram serveri bot so'raydi (getUpdates)
Sodda: domen/SSL/public URL kerak emas; lokal dev'da ishlaydi
Bot doim so'rab turadi; bitta instansiya
2. WEBHOOK — Telegram update'ni SIZNING URL'ingizga o'zi yuboradi (push)
Foydalanuvchi Telegram serveri POST https://senit.uz/webhook
Tez, samarali, masshtablanadi (production)
Public HTTPS URL + SSL kerak (domen/deploy — 10)Qaysi: dev/o'rganish — polling (sodda,
bot.launch()); production — webhook (tez, masshtab — 2.14). Bu — 5.13'dagi polling vs WebSocket bilan o'xshash mantiq, lekin bu yerda Telegram serveri o'rtada.
2.4. Ikki kutubxona: node-telegram-bot-api vs Telegraf
Node.js'da bot yozishning ikki asosiy kutubxonasi:
node-telegram-bot-api — eski, mashhur, oddiy; event-based (bot.on)
past darajali, ko'p narsa qo'lda
Telegraf — zamonaviy, framework; middleware (Express kabi — 5.6)
Context, Scenes, Sessions tayyor; TypeScript-firstTavsiya: Telegraf — zamonaviy, kuchli (middleware, scenes, sessiya, TypeScript — 7). Express'ni bilgan odam 5.6-bob uchun tanish (middleware arxitekturasi). Bu bobda asosan Telegrafni o'rganamiz; node-telegram-bot-api'ni ham ko'rsatamiz (eski loyihalarda uchraydi). NestJS'da
nestjs-telegraf8.20-bob.
2.5. Telegraf — Context (ctx) tushunchasi
Telegraf har update uchun Context (kontekst — ctx) obyekti yaratadi (telegraf docs). ctx — update haqidagi hamma narsa + javob berish metodlari (Express'dagi req+res kabi — 5.6):
bot.on("text", (ctx) => {
ctx.message.text // kelgan xabar matni
ctx.from // kim yubordi (id, ism, username)
ctx.chat // qaysi chat (id)
ctx.reply("Salom"); // javob yuborish (eng muhim metod)
});
ctx— botning "qo'li va ko'zi": u orqali kim, nima yuborganini bilasiz (ctx.from,ctx.message) va javob berasiz (ctx.reply). Deyarli hamma ishctxorqali.
2.6. Middleware arxitekturasi (Express ruhida — 5.6)
Telegraf — middlewarega asoslangan (Express kabi — 5.6, telegraf docs): har update bir nechta funksiyadan ketma-ket o'tadi; har biri next() bilan keyingisiga uzatadi:
// Har update'da ishlaydi (logging, auth — 5.6 ruhida)
bot.use(async (ctx, next) => {
console.log(`${ctx.from.id} dan update`); // log (5.12)
await next(); // keyingi handler'ga (5.6)
});Bu — 5.6'da o'rgangan middleware tushunchasining aynan o'zi, lekin Telegram update'lari uchun. Auth, logging, sessiya — hammasi middleware.
2.7. Buyruqlar (commands — /start, /help)
Buyruq — / bilan boshlanadigan maxsus xabar (/start, /help, /buyurtma). Telegraf ularni alohida tinglaydi:
bot.start((ctx) => ctx.reply("Xush kelibsiz!")); // /start (maxsus — birinchi ochilganda)
bot.help((ctx) => ctx.reply("Yordam: ...")); // /help
bot.command("buyurtma", (ctx) => ctx.reply("Buyurtma...")); // /buyurtma (ixtiyoriy nom)
/start— eng muhim buyruq: foydalanuvchi botni birinchi marta ochganda avtomatik yuboriladi. Bu yerda salomlashish, ro'yxatga olish, asosiy menyu ko'rsatiladi./startba'zan parametr bilan keladi (/start ref123— referal —ctx.startPayload).
2.8. Xabarlarni tinglash (hears, on)
Oddiy matn, rasm, joylashuv kabi xabarlarni tinglash:
bot.hears("salom", (ctx) => ctx.reply("Va alaykum salom")); // aniq matn
bot.hears(/narx/i, (ctx) => ctx.reply("Narxlar...")); // RegEx (2.13-JS)
bot.on("text", (ctx) => ctx.reply(`Siz: ${ctx.message.text}`)); // har qanday matn
bot.on("photo", (ctx) => ctx.reply("Rasm qabul qilindi")); // rasm
bot.on("contact", (ctx) => ctx.reply("Raqam olindi")); // telefon (klaviatura — 2.10)Tartib muhim: Telegraf yuqoridan pastga tekshiradi.
bot.on("text")hamma matnni ushlaydi — uni eng oxirga qo'ying (aks holdahearsishlamaydi).
2.9. Javob berish metodlari (reply oilasi)
ctxning javob metodlari (telegraf docs):
ctx.reply("matn"); // oddiy matn
ctx.reply("*qalin*", { parse_mode: "Markdown" }); // formatlash (2.15)
ctx.replyWithPhoto({ url: "..." }); // rasm
ctx.replyWithDocument({ source: "fayl.pdf" }); // hujjat
ctx.replyWithLocation(41.3, 69.2); // joylashuv (xarita)
ctx.editMessageText("yangi matn"); // xabarni tahrirlash (inline tugma bilan — 2.11)
ctx.answerCbQuery("Bajarildi!"); // callback javobi (2.11)Fayl yuborish —
sourcevsurl:{ source: "fayl.pdf" }— diskdagi fayl (yokiBuffer/Stream);{ url: "https://..." }— Telegram'ning o'zi yuklab oladi. Bir marta yuborilgan fayl uchun Telegramfile_idqaytaradi — keyin shu id'ni (URL emas) qayta yuborsangiz, fayl qayta yuklanmaydi (tezroq, trafik tejaladi).
Fayl qabul qilish (download): foydalanuvchi yuborgan rasm/hujjatni serverga olish uchun avval
file_id, so'ng havola olinadi:jsbot.on("photo", async (ctx) => { const rasmlar = ctx.message.photo; // bir nechta o'lcham (kichikdan kattagacha) const fileId = rasmlar[rasmlar.length - 1].file_id; // eng katta o'lcham const link = await ctx.telegram.getFileLink(fileId); // vaqtinchalik yuklash havolasi // link.href'ni fetch 5.11-bob bilan yuklab, diskka/S3'ga saqlang await ctx.reply("Rasm qabul qilindi"); });Hujjat uchun
ctx.message.document.file_id. Telegram havolasi vaqtinchalik — darhol yuklab oling, saqlab qo'ymang.
2.10. Reply Keyboard (oddiy klaviatura)
Reply keyboard — xabar yozish joyi o'rnida chiqadigan tugmalar (telegraf Markup). Tugma bosilsa — uning matni xabar sifatida yuboriladi:
import { Markup } from "telegraf";
ctx.reply("Tanlang:", Markup.keyboard([
[" Buyurtma", " Aloqa"], // birinchi qator (ikki tugma)
[" Ma'lumot"], // ikkinchi qator
]).resize()); // ekranga moslab kichraytirish
// Maxsus tugmalar:
Markup.keyboard([
[Markup.button.contactRequest(" Raqamni yuborish")], // telefon so'rash (2.8)
[Markup.button.locationRequest(" Joylashuv")], // joylashuv so'rash
]).resize();Reply keyboard — asosiy menyu uchun (doimo ko'rinib turadigan tugmalar). Tugma bosilsa — matn yuboriladi, uni
hearsbilan ushlaysiz 2.8-bob.
2.11. Inline Keyboard va Callback Query (eng muhim)
Inline keyboard — xabarning ostiga biriktirilgan tugmalar. Bosilganda matn yubormaydi, balki callback query (maxfiy signal) yuboradi — bot uni ushlab, reaksiya bildiradi (telegraf docs):
import { Markup } from "telegraf";
ctx.reply("Mahsulotni tanlang:", Markup.inlineKeyboard([
[Markup.button.callback(" Sotib olish", "sotib_1")], // callback_data: "sotib_1"
[Markup.button.callback(" Saralash", "saralash_1")],
[Markup.button.url(" Sayt", "https://senit.uz")], // havola (callback emas)
]));
// Callback'ni ushlash (tugma bosilganda)
bot.action("sotib_1", async (ctx) => {
await ctx.answerCbQuery("Savatga qo'shildi!"); // MAJBURIY (yuqoridagi "soat" yo'qoladi)
await ctx.editMessageText(" Savatga qo'shildi"); // xabarni yangilash (2.9)
});
// Dinamik callback (RegEx bilan — ID o'zgaruvchan)
bot.action(/sotib_(\d+)/, async (ctx) => {
const id = ctx.match[1]; // tugmadagi ID (2.13-JS)
await ctx.answerCbQuery();
await ctx.reply(`${id}-mahsulot tanlandi`);
});
answerCbQuery()MAJBURIY: inline tugma bosilganda, tugmada "yuklanmoqda" aylanasi paydo bo'ladi.ctx.answerCbQuery()uni to'xtatadi (ixtiyoriy matn/popup bilan). Chaqirmasangiz — foydalanuvchi tugma "osilib qolgan"dek ko'radi.Reply vs Inline farqi: reply keyboard — matn yuboradi (menyu); inline keyboard — callback yuboradi, xabar ostida turadi, tahrirlanadi (interaktiv — sotib olish, sahifalash, tasdiqlash).
2.12. Sessiya (session) — foydalanuvchi holatini saqlash
Bot holatsiz (stateless) — har update mustaqil. Lekin ko'p bot ko'p qadamli (ism so'ra telefon so'ra manzil so'ra). Buning uchun sessiya — har foydalanuvchi uchun ma'lumot saqlash (telegraf session):
import { session } from "telegraf";
bot.use(session()); // sessiya middleware (2.6)
bot.on("text", (ctx) => {
ctx.session ??= {}; // boshlang'ich (2.1-JS)
ctx.session.count = (ctx.session.count || 0) + 1; // har foydalanuvchi uchun alohida
ctx.reply(`Siz ${ctx.session.count} marta yozdingiz`);
});Default sessiya — XOTIRADA (telegraf docs): bot qayta ishga tushsa, yo'qoladi. Production'da Redis 5.21-bob yoki DB (6) sessiyasi:
@telegraf/sessionRedis/Postgres bilan. Webhook'da ko'p instansiya bo'lsa — shared storage (Redis) majburiy 2.14-bob.
2.13. Scenes (sahnalar) — ko'p qadamli dialoglar
Scene (sahna) — ko'p qadamli muloqotni boshqarish (ro'yxatdan o'tish: ism telefon manzil). Telegraf ikki xil scene beradi (telegraf scenes):
BaseScene — kirish/chiqish + o'z handlerlari (erkin boshqaruv)
WizardScene — qadamlar ketma-ketligi (1-qadam 2-qadam ...) — sehrgarWizard Scene — eng qulay ko'p qadamli forma uchun: har qadam — funksiya;
ctx.wizard.next()keyingi qadamga o'tkazadi. Scene'lar ichida sessiya ishlatiladi 2.12-bob — shuning uchun sessiya middleware kerak. Scene'larStagega ro'yxatdan o'tkaziladi.
2.14. Webhook — production rejimi (chuqur)
Production'da (10) webhook — Telegram update'ni sizning HTTPS URL'ingga yuboradi 2.3-bob. Telegraf'ni Express 5.6-bob bilan ulash:
// Telegraf webhook'ni Express route sifatida (5.6)
app.use(bot.webhookCallback("/telegram-webhook")); // bu yo'lga Telegram POST qiladi
await bot.telegram.setWebhook("https://senit.uz/telegram-webhook"); // Telegram'ga URL beringWebhook'da bot stateless bo'lsin yoki shared storage (Redis) ishlatsin (manbalar): har update boshqa instansiyaga (pod) tushishi mumkin (10.8: Kubernetes). Xotira sessiyasi ishlamaydi — Redis 5.21-bob. Polling'dan webhook'ga o'tish — deploy paytida (10).
2.15. Formatlash (Markdown / HTML)
Xabarni chiroyli qilish (qalin, kursiv, kod, havola — telegram docs):
ctx.reply("*Qalin* _kursiv_ `kod`", { parse_mode: "Markdown" });
ctx.reply("<b>Qalin</b> <i>kursiv</i> <a href='url'>havola</a>", { parse_mode: "HTML" });
ctx.replyWithMarkdownV2("Narx: *50 000* so'm");MarkdownV2'da maxsus belgilar (
.,-,!,() escape qilinishi kerak (\\.) — aks holda xato. Murakkab matnda HTML parse_mode ko'pincha qulayroq (kamroq escape muammosi).
2.16. Xatolarni boshqarish (5.10)
Bot xatolari ilovani buzmasligi kerak (foydalanuvchi davom etadi):
bot.catch((err, ctx) => { // global xato handler (5.10 ruhida)
console.error(`Xato (${ctx.updateType}):`, err); // log (5.12)
ctx.reply("Kechirasiz, xatolik yuz berdi. Qayta urinib ko'ring.");
});2.17. Backend/DB bilan integratsiya (real bot)
Real bot — ma'lumotni DB'da (6) saqlaydi, boshqa servislar bilan ishlaydi:
Foydalanuvchi ro'yxati DB (6): users (telegramId, ism, telefon)
Buyurtmalar DB: orders; admin'ga bildirishnoma 2.11-bob
SMS tasdiqlash OTP (5.16, 5.18: Eskiz)
To'lov Payme/Click integratsiyasi
Admin panel web (React — 11) + bot bir DB'ni ishlatadiBot — backend mantig'ining (5.1–5.12) Telegram interfeysi. Bir xil service/DB'ni REST API 5.7-bob va bot birga ishlatishi mumkin (mijoz bot orqali, admin web orqali).
2.18. Xavfsizlik va best practices (14)
Token .env'da (14, 5.8); git'ga qo'ymang 4.5-bob; sizsa /revoke
Kelgan ma'lumotni validatsiya (telefon, matn — 5.9, 14)
Admin amallarini himoyalang (faqat admin ID — middleware, 2.6)
Rate limiting (spam — 5.20); foydalanuvchi floodga qarshi
Sessiyani Redis'da (production — 2.12, 2.14)
Webhook URL maxfiy/tasodifiy yo'l (14); secret_token tekshiring
answerCbQuery doim chaqiring 2.11-bob
Xatoni bot.catch bilan ushlang (2.16)3. Sintaksis — tez ma'lumotnoma
import { Telegraf, Markup, session, Scenes } from "telegraf";
const bot = new Telegraf(process.env.BOT_TOKEN); // (5.8)
bot.use(session()); // sessiya (2.12)
bot.start((ctx) => ctx.reply("...")); // /start (2.7)
bot.command("nom", (ctx) => {...}); // /nom
bot.hears("matn", (ctx) => {...}); // matn (2.8)
bot.on("text", (ctx) => {...}); // har matn (oxirda!)
bot.action("data", (ctx) => {...}); // inline callback (2.11)
ctx.reply("matn", Markup.inlineKeyboard([...])); // tugma (2.11)
ctx.answerCbQuery(); // callback javobi (MAJBURIY — 2.11)
bot.catch((err, ctx) => {...}); // xato (2.16)
bot.launch(); // polling (dev — 2.3)
// yoki: app.use(bot.webhookCallback("/path")) (webhook — 2.14)
process.once("SIGINT", () => bot.stop()); // graceful (5.10)4. Batafsil kod namunalari
Misol 1 — Minimal bot (node-telegram-bot-api — 2.4)
// Eski, oddiy kutubxona (eski loyihalarda uchraydi — 2.4)
import TelegramBot from "node-telegram-bot-api";
const bot = new TelegramBot(process.env.BOT_TOKEN, { polling: true }); // (2.3, 5.8)
bot.onText(/\/start/, (msg) => { // /start (RegEx)
bot.sendMessage(msg.chat.id, "Salom! Men botman."); // chat.id ga javob
});
bot.on("message", (msg) => {
if (msg.text === "salom") bot.sendMessage(msg.chat.id, "Va alaykum");
});
// Past darajali: chat.id'ni qo'lda boshqarasiz, middleware/scene yo'qMisol 2 — Minimal Telegraf bot (2.4, 2.5)
import { Telegraf } from "telegraf";
const bot = new Telegraf(process.env.BOT_TOKEN); // (5.8)
bot.start((ctx) => ctx.reply(`Salom, ${ctx.from.first_name}!`)); // /start (2.7)
bot.help((ctx) => ctx.reply("Yordam: /start, /menyu")); // /help
bot.on("text", (ctx) => ctx.reply(`Siz yozdingiz: ${ctx.message.text}`)); // (2.8)
bot.launch(); // polling (dev — 2.3)
console.log("Bot ishga tushdi");
// Graceful shutdown (5.10)
process.once("SIGINT", () => bot.stop("SIGINT"));
process.once("SIGTERM", () => bot.stop("SIGTERM"));Misol 3 — Buyruqlar va matn tinglash (2.7, 2.8)
bot.start((ctx) => ctx.reply("Xush kelibsiz! /menyu ni bosing")); // (2.7)
bot.command("menyu", (ctx) => ctx.reply(" Menyu: Taomlar, Ichimliklar"));
bot.command("aloqa", (ctx) => ctx.reply(" +998 90 123 45 67"));
bot.hears("salom", (ctx) => ctx.reply("Va alaykum salom! ")); // aniq (2.8)
bot.hears(/narx|qancha/i, (ctx) => ctx.reply("Narxlar /menyu da")); // RegEx (2.8)
// Bu OXIRDA — hamma matnni ushlaydi (2.8)
bot.on("text", (ctx) => ctx.reply("Tushunmadim. /menyu ni bosing"));Misol 4 — Reply keyboard (asosiy menyu — 2.10)
import { Markup } from "telegraf";
bot.start((ctx) =>
ctx.reply("Asosiy menyu:", Markup.keyboard([
[" Buyurtma berish", " Savatim"],
[" Aloqa", " Biz haqimizda"],
[Markup.button.contactRequest(" Raqamni ulashish")], // telefon (2.10)
]).resize()) // ekranga moslash
);
// Klaviatura tugmalarini hears bilan ushlash (2.8)
bot.hears(" Buyurtma berish", (ctx) => ctx.reply("Mahsulotni tanlang..."));
bot.hears(" Aloqa", (ctx) => ctx.reply("+998 90 123 45 67"));
bot.on("contact", (ctx) => // telefon kelganda (2.8)
ctx.reply(`Rahmat! Raqamingiz: ${ctx.message.contact.phone_number}`)
);Misol 5 — Inline keyboard + callback (2.11)
import { Markup } from "telegraf";
const mahsulotlar = [
{ id: 1, nom: "Olma", narx: 12000 },
{ id: 2, nom: "Banan", narx: 18000 },
];
bot.command("mahsulotlar", (ctx) => {
// Har mahsulot uchun inline tugma (2.11)
const tugmalar = mahsulotlar.map((m) =>
[Markup.button.callback(`${m.nom} — ${m.narx} so'm`, `sotib_${m.id}`)]
);
ctx.reply("Mahsulotlar:", Markup.inlineKeyboard(tugmalar));
});
// Callback'ni dinamik ushlash (ID bilan — 2.11)
bot.action(/sotib_(\d+)/, async (ctx) => {
const id = Number(ctx.match[1]); // RegEx guruh (2.13-JS)
const m = mahsulotlar.find((x) => x.id === id);
await ctx.answerCbQuery(`${m.nom} savatga qo'shildi!`); // MAJBURIY (2.11)
await ctx.editMessageText(` ${m.nom} (${m.narx} so'm) savatga qo'shildi`); // (2.9)
});Misol 6 — Sessiya bilan holat saqlash (2.12)
import { Telegraf, session } from "telegraf";
const bot = new Telegraf(process.env.BOT_TOKEN);
bot.use(session({ defaultSession: () => ({ savat: [] }) })); // sessiya (2.12)
bot.action(/qosh_(\d+)/, async (ctx) => {
const id = Number(ctx.match[1]);
ctx.session.savat.push(id); // foydalanuvchi savatiga
await ctx.answerCbQuery("Qo'shildi");
await ctx.reply(`Savatda ${ctx.session.savat.length} ta mahsulot`);
});
bot.command("savat", (ctx) => {
const soni = ctx.session?.savat?.length || 0;
ctx.reply(soni ? `Savatda ${soni} ta` : "Savat bo'sh");
});
// Production: sessiyani Redis'da (2.12, 2.14, 5.21)Misol 7 — Wizard Scene (ro'yxatdan o'tish — 2.13)
import { Telegraf, Scenes, session, Markup } from "telegraf";
const bot = new Telegraf(process.env.BOT_TOKEN);
// Ko'p qadamli ro'yxatdan o'tish (ism telefon tasdiq — 2.13)
const royxat = new Scenes.WizardScene(
"royxat", // scene nomi
// 1-qadam: ism so'rash
(ctx) => {
ctx.reply("Ismingizni kiriting:");
return ctx.wizard.next(); // keyingi qadamga (2.13)
},
// 2-qadam: ismni saqlab, telefon so'rash
(ctx) => {
ctx.wizard.state.ism = ctx.message.text; // wizard holati
ctx.reply("Telefon raqamingizni yuboring:",
Markup.keyboard([[Markup.button.contactRequest(" Yuborish")]]).resize());
return ctx.wizard.next();
},
// 3-qadam: telefonni saqlab, tugatish
async (ctx) => {
const telefon = ctx.message.contact?.phone_number || ctx.message.text;
const { ism } = ctx.wizard.state;
await User.create({ telegramId: ctx.from.id, ism, telefon }); // DB (6, 2.17)
await ctx.reply(` Ro'yxatdan o'tdingiz!\nIsm: ${ism}\nTel: ${telefon}`,
Markup.removeKeyboard());
return ctx.scene.leave(); // scene'dan chiqish
}
);
const stage = new Scenes.Stage([royxat]); // scene'larni ro'yxatga oling
bot.use(session()); // scene sessiya talab qiladi (2.13)
bot.use(stage.middleware());
bot.command("royxat", (ctx) => ctx.scene.enter("royxat")); // scene'ga kirishMisol 8 — Base Scene (2.13)
import { Scenes } from "telegraf";
const aloqaScene = new Scenes.BaseScene("aloqa");
aloqaScene.enter((ctx) => ctx.reply("Xabaringizni yozing (chiqish: /bekor):"));
aloqaScene.command("bekor", (ctx) => { // scene ichida buyruq
ctx.reply("Bekor qilindi");
return ctx.scene.leave();
});
aloqaScene.on("text", async (ctx) => { // matn kelganda
await Feedback.create({ userId: ctx.from.id, matn: ctx.message.text }); // DB (6)
await ctx.reply(" Xabaringiz yuborildi. Rahmat!");
return ctx.scene.leave(); // chiqish
});
// Stage'ga qo'shish: new Scenes.Stage([royxat, aloqaScene])Misol 9 — Middleware (auth/logging — 2.6)
// Logging middleware (har update — 2.6, 5.12)
bot.use(async (ctx, next) => {
const boshlandi = Date.now();
await next(); // keyingi handler (5.6)
console.log(`${ctx.updateType} (${ctx.from?.id}) — ${Date.now() - boshlandi}ms`);
});
// Admin middleware (faqat admin — 2.18, 14)
const ADMINLAR = [123456789]; // admin Telegram ID'lari (.env — 5.8)
const adminOnly = async (ctx, next) => {
if (!ADMINLAR.includes(ctx.from.id)) {
return ctx.reply(" Ruxsat yo'q"); // rad (14)
}
await next();
};
bot.command("statistika", adminOnly, async (ctx) => { // faqat admin (5.6: zanjir)
const soni = await User.count(); // DB (6)
ctx.reply(`Jami foydalanuvchi: ${soni}`);
});Misol 10 — Xato handling + bot.catch (2.16)
bot.catch((err, ctx) => { // global (2.16, 5.10)
console.error(`Xato [${ctx.updateType}]:`, err); // log (5.12)
ctx.reply(" Xatolik yuz berdi. Birozdan keyin urinib ko'ring.")
.catch(() => {}); // javob ham xato bersa, e'tiborsiz
});
// Handler ichida ham try/catch (muhim amallar — 5.10)
bot.command("buyurtma", async (ctx) => {
try {
const buyurtma = await Order.create({ userId: ctx.from.id }); // DB (6)
await ctx.reply(` Buyurtma #${buyurtma.id} qabul qilindi`);
} catch (err) {
await ctx.reply(" Buyurtma berishda xato");
throw err; // bot.catch'ga (2.16)
}
});Misol 11 — Webhook (production — 2.14)
import express from "express";
import { Telegraf } from "telegraf";
import { config } from "./config/index.js"; // (5.8)
const bot = new Telegraf(config.botToken);
const app = express();
bot.start((ctx) => ctx.reply("Salom!"));
// Webhook'ni Express route sifatida (5.6, 2.14)
const WEBHOOK_PATH = `/tg/${config.webhookSecret}`; // tasodifiy yo'l (14)
app.use(bot.webhookCallback(WEBHOOK_PATH));
app.listen(config.port, async () => {
// Telegram'ga URL'ni ayt (2.14)
await bot.telegram.setWebhook(`${config.publicUrl}${WEBHOOK_PATH}`);
console.log("Bot webhook rejimida");
});
// Sessiya Redis'da bo'lsin (ko'p instansiya — 2.14, 5.21)Misol 12 — Real bot: buyurtma + admin bildirishnoma + SMS (2.17)
import { Telegraf, Markup, Scenes, session } from "telegraf";
const buyurtmaScene = new Scenes.WizardScene(
"buyurtma",
(ctx) => { ctx.reply("Mahsulot nomi?"); return ctx.wizard.next(); },
(ctx) => {
ctx.wizard.state.mahsulot = ctx.message.text;
ctx.reply("Manzilingiz?");
return ctx.wizard.next();
},
async (ctx) => {
const { mahsulot } = ctx.wizard.state;
const manzil = ctx.message.text;
// 1. DB'ga saqlash (6, 2.17)
const buyurtma = await Order.create({
userId: ctx.from.id, mahsulot, manzil, holat: "yangi",
});
// 2. Mijozga tasdiq
await ctx.reply(` Buyurtma #${buyurtma.id} qabul qilindi!`);
// 3. Admin'ga real-time bildirishnoma (2.11)
await ctx.telegram.sendMessage(config.adminChatId,
` Yangi buyurtma #${buyurtma.id}\nMahsulot: ${mahsulot}\nManzil: ${manzil}`,
Markup.inlineKeyboard([
[Markup.button.callback(" Tasdiqlash", `tasdiq_${buyurtma.id}`)],
]));
// 4. SMS yuborish (5.18: Eskiz) — mijozga
// await smsService.send(user.telefon, `Buyurtma #${buyurtma.id} qabul qilindi`);
return ctx.scene.leave();
}
);
// Admin tasdiqlasa (2.11)
bot.action(/tasdiq_(\d+)/, async (ctx) => {
await Order.update(ctx.match[1], { holat: "tasdiqlandi" }); // DB (6)
await ctx.answerCbQuery("Tasdiqlandi");
await ctx.editMessageText(ctx.update.callback_query.message.text + "\n\n TASDIQLANDI");
});5. To'g'ri va noto'g'ri holatlar
1) Token'ni kodga yozish
// token kodda git'ga ketadi (14, 2.2, 4.5)
const bot = new Telegraf("123456:AbCdef...");
// .env'da (5.8)
const bot = new Telegraf(process.env.BOT_TOKEN);2) answerCbQuery'ni chaqirmaslik
// tugma "osilib" qoladi (2.11)
bot.action("x", (ctx) => ctx.reply("..."));
// answerCbQuery
bot.action("x", async (ctx) => { await ctx.answerCbQuery(); await ctx.reply("..."); });3) bot.on("text") ni boshiga qo'yish
// hamma matnni ushlaydi, hears/command ishlamaydi (2.8)
bot.on("text", ...); bot.hears("salom", ...);
// on("text") OXIRDA
bot.hears("salom", ...); bot.command("x", ...); bot.on("text", ...);4) Xotira sessiyasini production'da ishlatish
default (xotira) sessiya + webhook/ko'p instansiya holat yo'qoladi (2.12, 2.14)
Redis sessiya (5.21)5) Kelgan ma'lumotni tekshirmaslik
// telefon formatini tekshirmasdan DB'ga (14, 5.9)
await User.create({ telefon: ctx.message.text });
// validatsiya (5.9)
if (!/^\+998\d{9}$/.test(telefon)) return ctx.reply("Noto'g'ri raqam");6) Xatoni ushlamaslik (bot qulaydi)
// bir xato butun botni to'xtatadi (2.16)
bot.command("x", async (ctx) => { await risky(); });
// bot.catch + try/catch (Misol 10)6. Keng tarqalgan xatolar va yechimlari
Xato 1 — 401 Unauthorized
Sababi: token noto'g'ri/yo'q 2.2-bob. Yechimi: .envdagi BOT_TOKENni tekshiring; BotFather'dan nusxa oling; dotenv yuklanganmi 5.8-bob.
Xato 2 — Bot javob bermaydi
Sababi: bot.launch() chaqirilmagan, yoki handler tartibi (on("text") boshida — 2.8), yoki polling/webhook ziddiyati. Yechimi: bot.launch(); tartibni to'g'irlang; bir vaqtda polling VA webhook ishlatmang.
Xato 3 — 409 Conflict: terminated by other getUpdates
Sababi: bir token bilan ikki bot instansiyasi polling qilmoqda 2.3-bob. Yechimi: faqat bitta instansiya; webhook va polling birga emas; eski jarayonni to'xtating.
Xato 4 — Inline tugma bosilganda hech narsa bo'lmaydi
Sababi: bot.action'dagi callback_data tugmadagiga mos emas, yoki answerCbQuery yo'q 2.11-bob. Yechimi: callback_datani moslang (RegEx — Misol 5); answerCbQuery chaqiring.
Xato 5 — 400: can't parse entities
Sababi: Markdown/HTML'da escape qilinmagan maxsus belgi 2.15-bob. Yechimi: maxsus belgilarni escape; yoki HTML parse_mode; yoki parse_modesiz oddiy matn.
Xato 6 — Scene/sessiya ishlamaydi
Sababi: session() middleware scene'dan oldin qo'shilmagan 2.13-bob. Yechimi: bot.use(session()) bot.use(stage.middleware()) tartibida.
Xato 7 — Webhook'da sessiya yo'qoladi
Sababi: xotira sessiyasi + ko'p instansiya 2.14-bob. Yechimi: Redis sessiya 5.21-bob.
7. Integratsiya — bu mavzu stack'ning qayerida uchraydi
- Async/await (2.11-JS): har bot amali async.
- EventEmitter/middleware (5.4, 5.6): Telegraf middleware modeli.
- Express 5.6-bob: webhook integratsiyasi 2.14-bob.
- Env 5.8-bob: token, webhook secret.
- Validatsiya 5.9-bob: kelgan ma'lumot (telefon, matn).
- Error handling 5.10-bob: bot.catch 2.16-bob.
- Logger 5.12-bob: middleware logging.
- OTP/SMS (5.16, 5.18): telefon tasdiqlash; Eskiz.
- Redis 5.21-bob: sessiya (production — 2.12, 2.14).
- DB (6): foydalanuvchi, buyurtma saqlash 2.17-bob.
- NestJS 8.20-bob: nestjs-telegraf — shu g'oya, dekorator bilan.
- Deploy (10): webhook, public URL, SSL.
8. Eng yaxshi amaliyotlar (best practices)
- Token .env'da (git'ga qo'ymang — 4.5, 14, 2.2); sizsa
/revoke. - Telegraf'ni tanlang (zamonaviy, middleware, scenes — 2.4); NestJS'da nestjs-telegraf.
bot.on("text")eng oxirda (command/hears'dan keyin — 2.8).answerCbQuerydoim chaqiring (inline tugma — 2.11).- Ko'p qadamli forma — Scene (Wizard — 2.13); sessiya middleware tartibi.
- Production sessiya — Redis (xotira emas — 2.12, 2.14, 5.21).
- Webhook (production), polling (dev — 2.3); ikkalasini birga ishlatmang.
- Kelgan ma'lumotni validatsiya (telefon, matn — 5.9, 14).
- Admin amallarini himoyalang (admin ID middleware — 2.18, 14).
bot.catch+ try/catch (bot qulamasin — 2.16).- Rate limiting (spam/flood — 5.20, 14).
- Formatlash uchun HTML (MarkdownV2 escape muammosidan — 2.15).
- Bot + REST/web bir DB/service (mijoz bot, admin web — 2.17).
9. Amaliy loyiha: "To'liq Telegram Do'kon Boti"
Telegram bot'ni real, professional darajada mustahkamlash.
Maqsad
Telegraf bilan ro'yxatdan o'tkazuvchi, mahsulot ko'rsatuvchi, buyurtma qabul qiluvchi va admin'ga bildirishnoma yuboruvchi to'liq do'kon botini qurish.
Talablar (requirements)
- Asosiy struktura:
/start(xush kelibsiz + reply keyboard menyu — 2.7, 2.10);/help. - Ro'yxatdan o'tish (Wizard Scene): ism telefon (contactRequest) DB'ga saqlash; takror ro'yxatga olmaslik (Misol 7, 2.13, 6).
- Mahsulotlar (inline keyboard): ro'yxat; har biri "Sotib olish" tugmasi (callback — Misol 5, 2.11).
- Savat (sessiya): mahsulot qo'shish/ko'rish; sessiyada saqlash (Misol 6, 2.12).
- Buyurtma (Wizard Scene): mahsulot + manzil DB mijozga tasdiq admin'ga bildirishnoma (inline tasdiq tugmasi — Misol 12, 2.17).
- Admin panel:
/statistika(foydalanuvchi/buyurtma soni) — faqat admin middleware (Misol 9, 2.18). - Validatsiya: telefon formati; bo'sh matn (5.9, 14).
- Xato handling:
bot.catch+ handler try/catch (Misol 10, 2.16). - Formatlash: chiroyli xabarlar (HTML/Markdown, emoji — 2.15).
- (Bonus) Sessiya — Redis (5.21, 2.12).
- (Bonus) Webhook rejimi (production — Misol 11, 2.14).
- (Bonus) SMS tasdiqlash (5.18: Eskiz) ro'yxatdan o'tishda.
Maslahatlar (hint)
- Token
.envda (2.2, 1-xato);dotenv5.8-bob. - Scene uchun:
session()stage.middleware()tartibi (2.13, 6-xato). - Inline callback:
bot.action(/sotib_(\d+)/)+answerCbQuery(2.11, 4-xato). bot.on("text")eng oxirda (2.8, 3-xato).- Telefon:
/^\+998\d{9}$/5.9-bob. - Admin:
ADMINLAR.includes(ctx.from.id)middleware 2.18-bob. - DB: bot + REST bir service/model ishlatsin (2.17, 6).
"Tayyor" mezonlari (acceptance criteria)
-
/startmenyu (reply keyboard) bilan ochiladi. - Wizard Scene ro'yxatdan o'tkazadi (ism+telefon DB).
- Mahsulotlar inline tugma bilan; callback ishlaydi (answerCbQuery).
- Savat sessiyada saqlanadi.
- Buyurtma DB'ga mijozga tasdiq admin'ga bildirishnoma.
- Admin statistikasi faqat admin'ga.
- Telefon/matn validatsiyasi.
- bot.catch xatolarni ushlaydi (bot qulamaydi).
- Xabarlar chiroyli formatlangan.
- (Bonus) Redis sessiya / webhook / SMS.
Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.
10. Xulosa va keyingi bobga ko'prik
Bu bobda O'zbekiston bozorida juda talab qilinadigan amaliy mavzuni — Telegram botni — chuqur o'rgandik:
- Bot qanday ishlaydi — Bot API orqali 2.1-bob; BotFather + token 2.2-bob; update'ni olish: polling (dev) vs webhook (production) (2.3, 2.14).
- node-telegram-bot-api vs Telegraf — Telegraf zamonaviy, middleware (Express ruhida — 2.4, 2.6); Context (ctx) 2.5-bob.
- Buyruqlar (
/start— 2.7), xabar tinglash (hears/on — 2.8), javob (reply oilasi — 2.9). - Reply keyboard (menyu — 2.10) vs Inline keyboard + callback (interaktiv,
answerCbQuery— 2.11). - Sessiya (holat — 2.12, production'da Redis); Scenes (Wizard/Base — ko'p qadamli forma — 2.13).
- Formatlash 2.15-bob, xato (bot.catch — 2.16), DB/SMS integratsiya (real bot — 2.17), xavfsizlik (token/admin/validatsiya — 2.18).
Keyingi bob — 5.15-bob: Autentifikatsiya — session, cookie, JWT, bcrypt. Endi backend'ning eng muhim, eng ko'p so'raladigan mavzusiga o'tamiz: autentifikatsiya (foydalanuvchi kimligini aniqlash). Parolni xavfsiz saqlash (bcrypt), session vs token yondashuvi, cookie, va JWT (JSON Web Token) — hammasi chuqur. Bu — har bir real ilovaning yuragi.
Foydalanilgan rasmiy/ishonchli manbalar
- telegraf.js.org — Telegraf (Context, middleware, Markup, Scenes, session)
- github.com/telegraf/telegraf — Telegraf framework; core.telegram.org/bots/api — Bot API
- grammy.dev / hostman — Polling vs Webhook; github.com/telegraf/telegraf-session-redis
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!