TelegramBotAPI Documentation

repository·master·Indexed 19 days ago

https://github.com/insanusmokrassar/ktgbotapi

A set of Kotlin libraries for interacting with the Telegram Bot API, supporting JVM and JavaScript. It provides high-level abstractions for handling updates, commands, and complex user interaction flows through a Behaviour Builder DSL, Finite State Machines (FSM), and Waiters for capturing specific content. The ecosystem includes tgbotapi.core for base functionality and tgbotapi.api for intuitive, named method signatures.

Tokens
8.7K
Snippets
32
Records
40
Agent score
65%

What's inside TelegramBotAPI

  1. Overview of TelegramBotAPI libraries

    master

    The TelegramBotAPI ecosystem is split into several modules to allow for granular dependency management:

    • TelegramBotAPI Core: The fundamental library components.
    • TelegramBotAPI API: Extensions for interacting with the API.
    • TelegramBotAPI Utils: Utility functions and helpers.
    • TelegramBotAPI Behaviour Builder: A framework for building bot behaviors.
    • TelegramBotAPI Behaviour Builder FSM: Finite State Machine (FSM) support for the Behaviour Builder.
  2. Compare tgbotapi.core and tgbotapi.api request methods

    master

    The tgbotapi.api library replaces the generic bot.execute(Request) pattern from tgbotapi.core with direct, named method calls that match Telegram's API terminology. This makes the code more readable and provides clearer signatures.

    tgbotapi.core (Generic)tgbotapi.api (Extension)
    bot.execute(GetMe)bot.getMe()
    bot.execute(SendTextMessage(chatId, text))bot.sendTextMessage(chat, text)
  3. Define message handling with Triggers

    master

    Triggers are mechanisms that listen for incoming messages. They can include filters for specific message types and filters for the context used in sub-contexts.

    For example, onText allows you to specify:

    • includeFilterByChatInBehaviourSubContext: If true, the sub-context will be filtered by the chat ID of the incoming message. If false, the sub-context receives all messages.
    • additionalFilter: A lambda to validate the incoming message before it reaches the main handler.

    The main lambda receives a BehaviourContext (e.g., TextMessage).

    telegramBotWithBehaviour(TOKEN) {
        onText(
            includeFilterByChatInBehaviourSubContext = true,
            additionalFilter = { message: TextMessage ->
                // check requirements here
            }
        ) { message: TextMessage -> 
            // actions and waiters go here
        }
    }
  4. How Types are represented in TelegramBotAPI

    master
    The library uses a type-safe, object-oriented approach to represent Telegram objects. Instead of a single monolithic object with many nullable fields (like the official Telegram Chat object), the library separates types into specific implementations. For example, the Chat interface is realized through specific types like PrivateChat, GroupChat, SupergroupChat, and ChannelChat, making the differences in content and behavior explicit and type-safe.
  5. Compare `safely` vs `safelyWithoutExceptions`

    master

    The library provides two distinct modes for local exception handling:

    1. safely: Used when you want to retrieve a value or throw an exception. If the error handler block is skipped or doesn't handle the error, it will throw an exception by default.
    2. safelyWithoutExceptions: Similar to safely, but instead of throwing an exception when something goes wrong, it returns a nullable result type (e.g., T?).
    // Example of 'safely' returning a specific type
    safely(
        {
            it.printStackTrace()
            "error"
        }
    ) {
        error("Hi :)") // emulate exception throwing
        "ok"
    } // result will be with type String
    
    // Example of 'safelyWithoutExceptions' returning nullable
    safelyWithouExceptions {
        // do something
    } // will returns nullable result type
  6. Configure global exception handling for a bot

    master

    To define a catch-all exception handler for your entire bot logic, provide a defaultExceptionsHandler lambda when building your bot's behavior. This handler is applied to the CoroutineContext of the provided scope. The library uses ContextSafelyExceptionHandler internally to ensure your custom handler is called when exceptions occur within your bot logic.

    val bot = telegramBot("TOKEN")
    
    bot.buildBehaviour (
        scope = scope,
        defaultExceptionsHandler = {
            it.printStackTrace()
        }
    ) {
        // ...
    }

    Alternatively, use telegramBotWithBehaviour:

    val bot = telegramBotWithBehaviour (
        "TOKEN",
        scope = scope,
        defaultExceptionsHandler = {
            it.printStackTrace()
        }
    ) {
        // ...
    }
  7. Retrieve updates via WebHooks (JVM-only)

    master

    Webhooks allow for automated update retrieval. Note that these extensions are currently limited to the JVM.

    Basic Webhook Listener: Use startListenWebhooks to start a server (e.g., using the CIO engine) that listens for updates.

    startListenWebhooks(
        8081,
        CIO // requires CIO engine dependency
    ) { 
        // updates arrive here one by one in $it
    }

    Ktor Integration: If you are using a Ktor application, you can integrate webhook handling directly into your existing routes instead of starting a separate server:

    • Route#includeWebhookHandlingInRoute: Includes webhook processing in your Ktor application.
    • Route#includeWebhookHandlingInRouteWithFlows: Similar to the above, but applies a FlowsUpdatesFilter to the block.

    Automated Setup: RequestsExecutor#setWebhookInfoAndStartListenWebhooks allows you to set up a full server and automatically sends the SetWebhook request to Telegram, verifying its success before starting.

    startListenWebhooks(8081, CIO) { /* updates */ }
  8. Retrieve updates via Long Polling

    master

    Long Polling is the simplest way to retrieve updates. You can use several extension functions depending on whether you want to pass a pre-created filter or a lambda.

    It is highly recommended to pass a CoroutineScope to manage the lifecycle of updates effectively.

    Using a pre-created filter:

    val filter = FlowsUpdatesFilter(64)
    bot.startGettingOfUpdatesByLongPolling(filter)

    Using a lambda directly:

    bot.startGettingOfUpdatesByLongPolling(
        { println("Received message update: $it") }
    )

    Using the startGettingFlowsUpdatesByLongPolling extension: This allows you to define the logic within a block where this refers to the filter:

    bot.startGettingFlowsUpdatesByLongPolling(
        scope = CoroutineScope(Dispatchers.Default)
    ) {
        textMessages().onEach { println("I have received text message: ${it.content}") }.launchIn(this)
    }
    val filter = FlowsUpdatesFilter(64)
    bot.startGettingOfUpdatesByLongPolling(filter)
  9. Use TelegramBotAPI Behaviour Builder for simplified bot logic

    master

    The tgbotapi.behaviour_builder extension provides a high-level DSL to handle bot steps and routine message processing, replacing manual Flow subscriptions. Instead of manually subscribing to messagesFlow, you can use telegramBotWithBehaviour(token) to define logic based on commands or text patterns.

    telegramBotWithBehaviour(token) {
        onCommand("start".regex) {
            execute(SendTextMessage(it.chat.id, "This bot can ..."))
        }
    }
  10. Handle updates using FlowsUpdatesFilter

    master

    To process incoming updates, you can use a FlowsUpdatesFilter. This allows you to separate different types of updates (including media groups) and use Kotlin Flows to filter, map, and react to specific data.

    Note: These features are part of the tgbotapi.utils dependency integration.

    // 1. Create a filter
    val filter = FlowsUpdatesFilter(100)
    
    // 2. Start getting updates with a specific scope
    bot.startGettingOfUpdates(
        filter,
        scope = CoroutineScope(Dispatchers.Default)
    )
    
    // 3. Use the filter's flows to process specific data
    filter.messageFlow.mapNotNull {
        it.data as? ContentMessage<*>
    }.onEach {
        println(it)
    }.launchIn(
        CoroutineScope(Dispatchers.Default)
    )