WisarWisar
Dasturlash kitobi/5-QISM — Nodejs22 daqiqa

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:

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

text
  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:AbCdefGhIJKlmNoPQRsTUVwxyZ

Token — 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 /revoke bilan yangisini oling.

2.3. Update'ni qabul qilish: Polling vs Webhook

Bot Telegram'dan update'ni ikki usul bilan oladi (grammy/hostman):

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

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

Tavsiya: 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-telegraf 8.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):

js
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 ish ctx orqali.

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:

js
// 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:

js
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. /start ba'zan parametr bilan keladi (/start ref123 — referal — ctx.startPayload).

2.8. Xabarlarni tinglash (hears, on)

Oddiy matn, rasm, joylashuv kabi xabarlarni tinglash:

js
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 holda hears ishlamaydi).

2.9. Javob berish metodlari (reply oilasi)

ctxning javob metodlari (telegraf docs):

js
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 — source vs url: { source: "fayl.pdf" } — diskdagi fayl (yoki Buffer/Stream); { url: "https://..." } — Telegram'ning o'zi yuklab oladi. Bir marta yuborilgan fayl uchun Telegram file_id qaytaradi — 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:

js
bot.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:

js
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 hears bilan ushlaysiz 2.8-bob.

2.11. Inline Keyboard va Callback Query (eng muhim)

Inline keyboardxabarning ostiga biriktirilgan tugmalar. Bosilganda matn yubormaydi, balki callback query (maxfiy signal) yuboradi — bot uni ushlab, reaksiya bildiradi (telegraf docs):

js
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):

js
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/session Redis/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):

text
  BaseScene    — kirish/chiqish + o'z handlerlari (erkin boshqaruv)
  WizardScene  — qadamlar ketma-ketligi (1-qadam  2-qadam  ...) — sehrgar

Wizard 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'lar Stagega 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:

js
// 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 bering

Webhook'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):

js
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):

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

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

Bot — 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)

text
   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

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

js
// 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'q

Misol 2 — Minimal Telegraf bot (2.4, 2.5)

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

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

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

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

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

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

Misol 8 — Base Scene (2.13)

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

js
// 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)

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

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

js
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

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

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

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

text
 default (xotira) sessiya + webhook/ko'p instansiya  holat yo'qoladi (2.12, 2.14)
 Redis sessiya (5.21)

5) Kelgan ma'lumotni tekshirmaslik

js
//  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)

js
//  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).
  • answerCbQuery doim 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)

  1. Asosiy struktura: /start (xush kelibsiz + reply keyboard menyu — 2.7, 2.10); /help.
  2. Ro'yxatdan o'tish (Wizard Scene): ism telefon (contactRequest) DB'ga saqlash; takror ro'yxatga olmaslik (Misol 7, 2.13, 6).
  3. Mahsulotlar (inline keyboard): ro'yxat; har biri "Sotib olish" tugmasi (callback — Misol 5, 2.11).
  4. Savat (sessiya): mahsulot qo'shish/ko'rish; sessiyada saqlash (Misol 6, 2.12).
  5. Buyurtma (Wizard Scene): mahsulot + manzil DB mijozga tasdiq admin'ga bildirishnoma (inline tasdiq tugmasi — Misol 12, 2.17).
  6. Admin panel: /statistika (foydalanuvchi/buyurtma soni) — faqat admin middleware (Misol 9, 2.18).
  7. Validatsiya: telefon formati; bo'sh matn (5.9, 14).
  8. Xato handling: bot.catch + handler try/catch (Misol 10, 2.16).
  9. Formatlash: chiroyli xabarlar (HTML/Markdown, emoji — 2.15).
  10. (Bonus) Sessiya — Redis (5.21, 2.12).
  11. (Bonus) Webhook rejimi (production — Misol 11, 2.14).
  12. (Bonus) SMS tasdiqlash (5.18: Eskiz) ro'yxatdan o'tishda.

Maslahatlar (hint)

  • Token .envda (2.2, 1-xato); dotenv 5.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)

  • /start menyu (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!
5.14-bob: Telegram bot — node-telegram-bot-api va Telegraf — Wisar