ExGram

Hex.pm Documentation Hex.pm Hex.pm Build Status

ExGram is a powerful Elixir library for building Telegram Bots. Use the low-level API for fine-grained control, or leverage the opinionated framework for rapid bot development.

Features

  • Automatic API Generation - Always up-to-date with the latest Telegram Bot API
  • Flexible DSL - Build responses elegantly with the context-based DSL
  • Polling & Webhooks - Choose the update method that fits your needs
  • Easy discovery of the API - Complete typespecs and documentation for all methods and models
  • Middleware System - Add authentication, logging, and custom processing
  • Message Entities Builder - Easily format messages without Markdown/HTML escaping
  • Multiple Bots - Run multiple different bots, or instances of the same bot in a single application
  • Production Ready - Battle-tested in real-world applications

Quick Start

Installation

Add to your mix.exs:

def deps do
  [
    {:ex_gram, "~> 0.64"},
    {:jason, "~> 1.4"},
    {:req, "~> 0.5"}  # HTTP adapter
  ]
end

Configure the adapter:

# config/config.exs
config :ex_gram, adapter: ExGram.Adapter.Req

Configure the formatter (Optional):

# .formatter.exs
[
    # ....
    import_deps: [:ex_gram] # Add :ex_gram here
]

Your First Bot

Generate a bot module:

mix bot.new

Add to your supervision tree:

# lib/my_app/application.ex
def start(_type, _args) do
  children = [
    ExGram,
    {MyApp.Bot, [method: :polling, token: "YOUR_BOT_TOKEN"]}
  ]

  Supervisor.start_link(children, strategy: :one_for_one)
end

Implement handlers:

defmodule MyApp.Bot do
  use ExGram.Bot, name: :my_bot, setup_commands: true

  import ExGram.Dsl.Keyboard

  command("start")
  command("help", description: "Show help")
  
  middleware(ExGram.Middleware.IgnoreUsername)  

  def handle({:command, :start, _}, context) do
    answer(context, "Welcome! I'm your bot.")
  end

  def handle({:command, :help, _}, context) do
    message = """
    Available commands:
    /start - Start the bot
    /help - Show this help
    """

    keyboard = 
      keyboard :inline do
        row do
          button "Test button", callback_data: "button"
        end
      end

    answer(context, message, reply_markup: keyboard)
  end

  def handle({:callback_query, %{data: "button"}}, context) do
    context
    |> answer_callback("Button clicked!")
    |> edit(:inline, "You clicked the button!")
  end
end

Run your bot:

mix run --no-halt

DSL Functions

The ExGram DSL builds actions on the context that execute after your handler returns.

Sending Messages

context 
|> answer("Hello!")
|> answer_document({:file, "/path/to/file.pdf"})

Inline Keyboards

  • With the DSL
import ExGram.Dsl.Keyboard

markup = 
  keyboard :inline do
    row do
      button "Button text", callback_data: "button"
    end
  end
  
answer(context, "Choose:", reply_markup: markup)
  • With a helper method
markup = create_inline_keyboard([
  [%{text: "Button", callback_data: "button"}]
])
answer(context, "Choose:", reply_markup: markup)

Editing & Deleting

edit(context, "Updated message")
edit_markup(context, new_keyboard)
delete(context)

Callback Queries & Inline Queries

answer_callback(context, "Processing...")
answer_inline_query(context, results)

Use steps results

context
|> answer("Important message!")
|> on_result(fn 
  {:ok, message}, name ->
    ExGram.pin_chat_message(message.chat.id, message.message_id, bot: name)
    
  error, _name ->
    error
end)

Extracting Information

extract_id(context)           # Chat ID
extract_user(context)         # User
extract_message_id(context)   # Message ID
extract_update_type(context)  # Update type
extract_message_type(context) # Message type

Low-Level API

Use ExGram as a library without the framework:

# Configure globally
config :ex_gram, token: "YOUR_TOKEN"

ExGram.send_photo(chat_id, {:file, "photo.jpg"})
ExGram.get_me()

# Or you can pass the token directly
ExGram.send_message(chat_id, "Hello!", token: "YOUR_TOKEN")

All methods return {:ok, result} | {:error, ExGram.Error.t()} and have bang variants:

{:ok, message} = ExGram.send_message(chat_id, "Hello")
message = ExGram.send_message!(chat_id, "Hello")  # Raises on error

See the Sending Messages guide for a complete reference or the Cheatsheet for a quick overview.

Documentation

Getting Started

Building Bots

Advanced

Deployment

  • Fly.io - Deploy your bot to production

Reference

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

Beer-Ware License. See LICENSE for details.