Defines a behaviour for Telegram bots and provides the main use macro.
When you use TelegramEx in your module, the macro injects:
Behaviour implementation - Sets
@behaviour TelegramExrequiring you to implementhandle_message/2andhandle_callback/2callbacks.Imports and aliases - Automatically imports
TelegramExandTelegramEx.FSM.defstate/2, and aliases commonly used modules (API,Config,FSM, and all builder modules).Child spec - Generates a
child_spec/1function that returns a supervisor child specification. This allows your bot module to be added directly to a supervision tree. The child spec startsTelegramEx.Serverwhich handles polling and message dispatch.Default implementations - Via
@before_compile, injects default implementations ofhandle_message/2andhandle_callback/2that return:ok. These are used as fallbacks if you don't define your own catch-all clauses.
Macro Options
:name(required) - Atom identifier for the bot, stored in@bot_namemodule attribute. Used for configuration lookup and FSM storage.:routers(optional) - List of router modules, stored in@routersmodule attribute. Routers are tried in order before the main bot module when handling updates.
Example
defmodule MyBot do
use TelegramEx, name: :my_bot, routers: [MyApp.AdminRouter]
def handle_message(%{text: "/start", chat: chat}, ctx) do
ctx
|> Message.text("Hello!")
|> Message.send(chat["id"])
end
def handle_callback(%{data: data}, ctx), do: :ok
endThis expands to approximately:
defmodule MyBot do
@behaviour TelegramEx
import TelegramEx
import TelegramEx.FSM, only: [defstate: 2]
alias TelegramEx.{API, Config, FSM}
alias TelegramEx.Builder.{Contact, Document, Location, Message, Photo, Sticker, Video}
@bot_name :my_bot
@routers [MyApp.AdminRouter]
def child_spec(_) do
%{
id: __MODULE__,
start: {TelegramEx.Server, :start_link, [__MODULE__, @bot_name, @routers]},
type: :worker
}
end
def handle_message(%{text: "/start", chat: chat}, ctx) do
# your implementation
end
def handle_callback(%{data: data}, ctx), do: :ok
# Injected by @before_compile as fallback
def handle_message(_message, _ctx), do: :ok
def handle_callback(_callback, _ctx), do: :ok
endThe generated child_spec/1 allows you to add the bot to your supervision tree:
children = [MyBot]
Supervisor.start_link(children, strategy: :one_for_one)When supervised, TelegramEx.Server starts and begins polling Telegram for updates,
calling your handle_message/2 and handle_callback/2 implementations.
Summary
Callbacks
Callback invoked when a callback query (inline button press) is received.
Callback invoked when a message is received.
Types
@type context() :: %{ :token => String.t(), :state => atom() | nil, :data => term(), optional(:message_thread_id) => integer(), optional(:payload) => map(), optional(:chat_id) => integer(), optional(:method) => String.t(), optional(:format) => :json | :multipart }
Context map passed to all handlers.
Contains bot token, FSM state/data, and builder accumulator.
@type handler_result() :: :ok | :pass | {:transition, new_state :: atom()} | {:transition, new_state :: atom(), data :: term()} | {:stay, data :: term()} | {:error, reason :: term()}
Return value from handlers indicating state transitions.
Callbacks
@callback handle_callback( callback :: TelegramEx.Types.CallbackQuery.t(), context :: context() ) :: handler_result()
Callback invoked when a callback query (inline button press) is received.
Parameters
callback- ATelegramEx.Types.CallbackQuerystructcontext- Context map with bot token, FSM state, and data
Returns
A handler_result/0 indicating how to handle the callback.
Example
def handle_callback(%{data: "confirm"} = callback, ctx) do
ctx
|> Message.text("Confirmed!")
|> Message.answer_callback_query(callback)
|> Message.send(callback.message.chat["id"])
end
@callback handle_message(message :: TelegramEx.Types.Message.t(), context :: context()) :: handler_result()
Callback invoked when a message is received.
Parameters
message- ATelegramEx.Types.Messagestruct containing the incoming messagecontext- Context map with bot token, FSM state, and data
Returns
A handler_result/0 indicating how to handle the message.
Example
def handle_message(%{text: "/start", chat: chat}, ctx) do
ctx
|> Message.text("Welcome!")
|> Message.send(chat["id"])
{:transition, :started}
end