grammY Telegram Bot Framework

repository·main·Indexed 11 days ago

https://github.com/grammyjs/grammY

A powerful and efficient Telegram Bot Framework for TypeScript and JavaScript, compatible with Node.js, Deno, and Cloudflare Workers. Version 1.45.1 features a robust middleware system via the Composer class, supporting specialized handlers like .command(), .hears(), and .callbackQuery(), as well as advanced routing, error boundaries, and concurrent middleware execution.

Tokens
28.1K
Snippets
95
Records
159
Agent score
86%

What's inside grammY

  1. Quickstart: Create your first Telegram bot

    main

    To create a basic Telegram bot using grammY, follow these steps:

    1. Obtain a Bot Token: Message @BotFather on Telegram to create a new bot and receive your API token.
    2. Install grammY: Use npm to install the package in your project directory.
    3. Initialize the Bot: Create a script (e.g., bot.js) using the Bot class.
    4. Register Listeners: Use .on() to handle specific updates, such as message:text.
    5. Start the Bot: Call .start() to begin long polling for updates.

    Note: This example uses Node.js. For Deno, import from https://deno.land/x/grammy/mod.ts.

    const { Bot } = require("grammy");
    
    // Create a bot object
    const bot = new Bot("YOUR_BOT_TOKEN");
    
    // Register listeners to handle messages
    bot.on("message:text", (ctx) => ctx.reply("Echo: " + ctx.message.text));
    
    // Start the bot (using long polling)
    bot.start();
  2. Use the grammY web bundle for Cloudflare Workers

    main

    If you are running your bot in a browser-compatible environment like Cloudflare Workers, you can use the web bundle included in the npm package. This allows you to import the Bot class directly from the grammy/web entry point.

    import { Bot } from "grammy/web";
  3. What is a Context object in grammY?

    main

    When your bot receives an update from Telegram, grammY wraps it in a Context object (commonly named ctx). This object is passed to all registered middleware and provides two primary capabilities:

    1. Access to the Update: ctx.update holds the raw update object. The context provides numerous shortcuts to access specific parts of the update (e.g., ctx.message, ctx.callbackQuery) regardless of whether it's a new message, an edited message, or a channel post.
    2. Access to the Bot API: ctx.api allows you to call any method of the Telegram Bot API directly. Additionally, the context provides high-level shortcuts for common actions, such as ctx.reply, which is a wrapper for ctx.api.sendMessage with the chat_id pre-filled.

    Context objects can also be used to store state (like sessions) or match information (like ctx.match for regular expression captures).

  4. What is middleware in grammY?

    main

    Middleware is a function (or a container for a function) that acts as a listener for updates. When an update occurs, grammY passes a context object (ctx) to the middleware. The context object contains information about the update (like ctx.message) and provides shortcuts like ctx.reply() to interact with the user without manually specifying chat IDs.

    To allow other middleware to run after the current one finishes its logic, you must call and await the next function provided as the second argument.

    bot.on('message', ctx => ctx.reply('I got your message!'))
    //                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    //                ^
    //                |
    //               This is middleware!
  5. Probe context objects with Context.has

    main

    The Context.has object provides utility functions to generate predicate functions for probing context objects. These predicates can be used to check if a context meets specific conditions.

    Calling a method directly on the context object (e.g., ctx.hasText(...)) is equivalent to using the predicate generated by Context.has (e.g., Context.has.text(...)(ctx)).

    // Using the predicate generator
    const hasText = Context.has.filterQuery(":text");
    if (hasText(ctx)) { /* ... */ }
    
    // Using the shorthand on the context object (equivalent)
    if (ctx.has(":text")) { /* ... */ }
  6. Secure webhooks using `secretToken`

    main

    To prevent unauthorized requests from reaching your bot, you can use the secretToken option. When configured, grammY performs a constant-time comparison between the provided secretToken and the value of the X-Telegram-Bot-Api-Secret-Token header sent by Telegram. This protects your bot against timing attacks.

    If the tokens do not match, the request is treated as unauthorized and the bot will not process the update.

  7. Use Webhook Reply optimization

    main

    If your bot runs on webhooks, you can use the canUseWebhookReply option and provide a WebhookReplyEnvelope. This allows grammY to perform up to one API call by including the result in the HTTP response of the webhook itself, saving an extra outgoing HTTP request.

    Important Limitations:

    1. You cannot handle errors for these calls (e.g., rate limits).
    2. You won't have access to the full response object (e.g., the returned Message object).
    3. Requests cannot be cancelled via AbortSignal.
    4. It only works if the payload can be sent as JSON.
    interface WebhookReplyEnvelope {
        send?: (payload: string) => void | Promise<void>;
    }
    
    // Example usage in configuration
    const options = {
        canUseWebhookReply: (method) => method === 'sendMessage',
        // ...
    };
  8. Use Context probing shortcuts for middleware filtering

    main

    The Context object (via its internal probing logic) provides predicate functions that can be used to test if a context matches specific criteria. These are used by the bot's listener methods to route updates to the correct handlers.

    Common probing methods include:

    • ctx.text(trigger): Tests if the message/caption contains the specified string or matches a RegExp.
    • ctx.command(command): Tests if the message contains a specific command (e.g., ctx.command('start')). Note: Do not include the / prefix when calling this.
    • ctx.reaction(reaction): Tests if a message reaction update matches a specific emoji or reaction type.
    • ctx.chatType(chatType): Tests if the update belongs to a specific chat type (e.g., private, group, supergroup).
    • ctx.callbackQuery(trigger): Tests if a callback query matches a string or RegExp.
    • ctx.inlineQuery(trigger): Tests if an inline query matches a string or RegExp.
    • ctx.filterQuery(query): A generic way to test the context against a FilterQuery.
  9. How API transformers work

    main

    A Transformer is a function that intercepts an API call. It receives the previous API call function (prev), the method name, the payload, and an AbortSignal. It must return a Promise that resolves to an ApiResponse.

    Transformers are executed in the order they are registered via .use(). This pattern allows you to build complex logic like rate limiting, custom retries, or telemetry on top of the raw Telegram API calls.

    type Transformer<R extends RawApi> = <M extends Methods<R>>(
        prev: ApiCallFn<R>,
        method: M,
        payload: Payload<M, R>,
        signal?: AbortSignal,
    ) => Promise<ApiResponse<ApiCallResult<M, R>>>;