Telego • Go Telegram Bot API
Telego is Telegram Bot API library for Golang with full API implementation (one-to-one)
The goal of this library was to create API with the same types and methods as actual Telegram Bot API.
Every type and method have been represented in types.go
and methods.go
files with mostly
all documentation from Telegram.
:warning: Telego is still in v0.x.x version, so do expect breaking changes! :warning:
For more detailed documentation, see docs at telego.pixelbox.dev.
Note: Telego uses fasthttp instead of net/http
and go-json instead of encoding/json
by default (both can be changed).
:clipboard: Table Of Content
Click to show • hide
:zap: Getting Started
How to get the library:
go get github.com/mymmrac/telego
Make sure you get the latest version to have all new features & fixes.
More examples can be seen here:
Click to show • hide
Note: Error handling may be missing in examples, but I strongly recommend handling all errors.
Generally, useful information about Telegram Bots and their features:
Click to show • hide
:jigsaw: Basic setup
▲ Go Up ▲
For start, you need to create an instance of your bot and
specify token.
package main
import (
"fmt"
"os"
"github.com/mymmrac/telego"
)
func main() {
botToken := os.Getenv("TOKEN")
bot, err := telego.NewBot(botToken, telego.WithDefaultDebugLogger())
if err != nil {
fmt.Println(err)
os.Exit(1)
}
botUser, err := bot.GetMe()
if err != nil {
fmt.Println("Error:", err)
}
fmt.Printf("Bot user: %+v\n", botUser)
}
:envelope_with_arrow: Getting updates
▲ Go Up ▲
In order to receive updates, you can use one of two methods:
- using long polling (
bot.UpdatesViaLongPolling
) - using webhook (
bot.UpdatesViaWebhook
)
Let's start from long polling (easier for local testing):
package main
import (
"fmt"
"os"
"github.com/mymmrac/telego"
)
func main() {
botToken := os.Getenv("TOKEN")
bot, err := telego.NewBot(botToken, telego.WithDefaultDebugLogger())
if err != nil {
fmt.Println(err)
os.Exit(1)
}
updates, _ := bot.UpdatesViaLongPolling(nil)
defer bot.StopLongPolling()
for update := range updates {
fmt.Printf("Update: %+v\n", update)
}
}
Webhook example (recommended way):
package main
import (
"fmt"
"os"
"github.com/mymmrac/telego"
)
func main() {
botToken := os.Getenv("TOKEN")
bot, err := telego.NewBot(botToken, telego.WithDefaultDebugLogger())
if err != nil {
fmt.Println(err)
os.Exit(1)
}
_ = bot.SetWebhook(&telego.SetWebhookParams{
URL: "https://example.com/bot" + bot.Token(),
})
info, _ := bot.GetWebhookInfo()
fmt.Printf("Webhook Info: %+v\n", info)
updates, _ := bot.UpdatesViaWebhook("/bot" + bot.Token())
go func() {
_ = bot.StartWebhook("localhost:443")
}()
defer func() {
_ = bot.StopWebhook()
}()
for update := range updates {
fmt.Printf("Update: %+v\n", update)
}
}
For running multiple bots from a single server, see this example.
Tip: For testing webhooks, you can use Ngrok to make a tunnel to your localhost,
and get a random domain available from the Internet.
It's as simple as ngrok http 8080
.
Or follow Telego + Ngrok example using ngrok/ngrok-go
for most convenient bot testing.
Tip: You may wish to use Let's Encrypt in order to generate your free TLS certificate.
:kite: Using Telegram methods
▲ Go Up ▲
All Telegram Bot API methods described in documentation can be
used by the library. They have the same names and the same parameters, parameters represented by struct with
name: <methodName>
+ Params
. If method doesn't have required parameters nil
value can be used as a parameter.
Note: types.go
and methods.go
were automatically generated
from documentation, and it's possible that they have errors or missing parts both in comments and
actual code. Feel free to report such things.
package main
import (
"fmt"
"os"
"github.com/mymmrac/telego"
tu "github.com/mymmrac/telego/telegoutil"
)
func main() {
botToken := os.Getenv("TOKEN")
bot, err := telego.NewBot(botToken, telego.WithDefaultDebugLogger())
if err != nil {
fmt.Println(err)
os.Exit(1)
}
botUser, _ := bot.GetMe()
fmt.Printf("Bot User: %+v\n", botUser)
updates, _ := bot.UpdatesViaLongPolling(nil)
defer bot.StopLongPolling()
for update := range updates {
if update.Message != nil {
chatID := update.Message.Chat.ID
sentMessage, _ := bot.SendMessage(
tu.Message(
tu.ID(chatID),
update.Message.Text,
),
)
fmt.Printf("Sent Message: %v\n", sentMessage)
}
}
}
:soap: Utility methods
▲ Go Up ▲
In Telego even though you have all types
and methods
available, it's often not so
convenient to use them directly. To solve this issues telegoutil
package was created. It contains
utility-helper function that will make your life a bit easier.
I suggest including it with alias to get cleaner code:
import tu "github.com/mymmrac/telego/telegoutil"
The package contains couple methods for creating send parameters with all required parameters like:
Message(chatID, text) => SendMessageParams
Photo(chatID, photoFile) => SendPhotoParams
Location(chatID, latitude, longitude) => SendLocationParams
- ...
Or other useful methods like:
ID(intID) => ChatID
File(namedReader) => InputFile
- ...
Utils related to methods
can be found in telegoutil/methods
, for
types
in telegoutil/types
, for handlers
in
telegoutil/handler
, for api
in telegoutil/api
.
Note: If you think that something can be added to telegoutil
package
fill free to create an issue or pull request with desired changes.
:mechanical_arm: Helper With...
methods
▲ Go Up ▲
Creating method parameters is sometimes bulky and not convenient, so you can use with
methods in combination with
utility
methods.
Here is a simple example of creating a message with a keyboard that has 4 buttons with different parameters.
package main
import (
"github.com/mymmrac/telego"
tu "github.com/mymmrac/telego/telegoutil"
)
func main() {
keyboard := tu.Keyboard(
tu.KeyboardRow(
tu.KeyboardButton("Button"),
tu.KeyboardButton("Poll Regular").
WithRequestPoll(tu.PollTypeRegular()),
),
tu.KeyboardRow(
tu.KeyboardButton("Contact").WithRequestContact(),
tu.KeyboardButton("Location").WithRequestLocation(),
),
).WithResizeKeyboard().WithInputFieldPlaceholder("Select something")
msg := tu.Message(
tu.ID(123),
"Hello World",
).WithReplyMarkup(keyboard).WithProtectContent()
bot.SendMessage(msg)
}
Those methods allow you to modify values without directly accessing them, also as you saw with
methods can be staked
one to another in order to update multiple values.
:sun_behind_large_cloud: Bot handlers
▲ Go Up ▲
Processing updates just in for loop is not the most pleasing thing to do, so Telego provides net/http
like handlers,
but instead of the path, you provide predicates.
One update will only match to the first handler whose predicates are satisfied, predicates checked in order of handler
registration (it's useful to first specify the most specific predicates and then more general).
Also, all handlers (but not their predicates) are processed in parallel.
I suggest including it with alias to get cleaner code:
import th "github.com/mymmrac/telego/telegohandler"
Here is an example of using handlers with long polling updates.
You can see the full list of available predicates in telegohandler/predicates
,
or define your own.
package main
import (
"fmt"
"os"
"github.com/mymmrac/telego"
th "github.com/mymmrac/telego/telegohandler"
tu "github.com/mymmrac/telego/telegoutil"
)
func main() {
botToken := os.Getenv("TOKEN")
bot, err := telego.NewBot(botToken, telego.WithDefaultDebugLogger())
if err != nil {
fmt.Println(err)
os.Exit(1)
}
updates, _ := bot.UpdatesViaLongPolling(nil)
bh, _ := th.NewBotHandler(bot, updates)
defer bh.Stop()
defer bot.StopLongPolling()
bh.Handle(func(bot *telego.Bot, update telego.Update) {
_, _ = bot.SendMessage(tu.Message(
tu.ID(update.Message.Chat.ID),
fmt.Sprintf("Hello %s!", update.Message.From.FirstName),
))
}, th.CommandEqual("start"))
bh.Handle(func(bot *telego.Bot, update telego.Update) {
_, _ = bot.SendMessage(tu.Message(
tu.ID(update.Message.Chat.ID),
"Unknown command, use /start",
))
}, th.AnyCommand())
bh.Start()
}
Also, just handling updates is useful, but handling specific updates like messages or callback queries in most of the
cases are more straightforward and provides cleaner code.
So Telego provides specific handles for all fields of telego.Update
. See the list of all available handler types in
telegohandler/update_handlers
, or define your own.
package main
import (
"fmt"
"github.com/mymmrac/telego"
th "github.com/mymmrac/telego/telegohandler"
tu "github.com/mymmrac/telego/telegoutil"
)
func main() {
bh.HandleMessage(func(bot *telego.Bot, message telego.Message) {
_, _ = bot.SendMessage(tu.Message(
tu.ID(message.Chat.ID),
fmt.Sprintf("Hello %s!", message.From.FirstName),
).WithReplyMarkup(tu.InlineKeyboard(
tu.InlineKeyboardRow(
tu.InlineKeyboardButton("Go!").WithCallbackData("go"),
)),
))
}, th.CommandEqual("start"))
bh.HandleCallbackQuery(func(bot *telego.Bot, query telego.CallbackQuery) {
_, _ = bot.SendMessage(tu.Message(tu.ID(query.Message.Chat.ID), "GO GO GO"))
_ = bot.AnswerCallbackQuery(tu.CallbackQuery(query.ID).WithText("Done"))
}, th.AnyCallbackQueryWithMessage(), th.CallbackDataEqual("go"))
}
One more important part of handlers are groups and middlewares.
Telego allows creating groups with and without predicates and attaching middleware to groups.
package main
import (
"fmt"
"github.com/mymmrac/telego"
th "github.com/mymmrac/telego/telegohandler"
)
func main() {
bh.Use(func(bot *telego.Bot, update telego.Update, next th.Handler) {
fmt.Println("Global middleware")
next(bot, update)
})
task := bh.Group(th.TextContains("task"))
task.Use(func(bot *telego.Bot, update telego.Update, next th.Handler) {
fmt.Println("Group-based middleware")
if len(update.Message.Text) < 10 {
next(bot, update)
}
})
task.HandleMessage(func(bot *telego.Bot, message telego.Message) {
fmt.Println("Task...")
})
}
:gear: Build configuration
▲ Go Up ▲
Telego supports multiple build configurations via Go's build tags
(right now only to change JSON encoding/decoding library):
Note: Use sonic
only on supported platforms as it has its own limitations, more
here.
:art: Contribution
Contribution guidelines listed here.
:star: Stargazers over time
Powered by caarlos0/starcharts
:closed_lock_with_key: License
Telego is distributed under MIT licence.