A small Haskell library with two focused additions for Telegram bots:
- Servant routing helpers for webhook endpoints keyed by a bot token
- Attoparsec-based parsers for Telegram slash commands and command arguments
The library is built around telegram-bot-simple, telegram-bot-api, and Servant.
This module provides a Servant combinator that takes a Token from the Servant context and turns it into a path segment.
The core API is:
fromToken :: Token -> ForToken a
type BotApi tokenType = ForToken tokenType :> ReqBody '[JSON] Update :> Post '[JSON] ()
botApi :: Proxy (BotApi tokenType)
server :: BotApp model action -> BotEnv model action -> Server (BotApi tokenType)
makeBotHandler :: MonadIO m => ClientEnv -> BotApp state update -> m (Update -> Handler ())server handles incoming Telegram Update values and dispatches produced actions asynchronously through telegram-bot-simple.
makeBotHandler constructs a fresh BotEnv, starts the background action-processing loop, and returns a webhook handler function.
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
import Network.Wai (Application)
import Servant
import Telegram.Bot.API (Token)
import Telegram.Bot.Extra.BotRoute
import Telegram.Bot.Simple (BotApp)
import Telegram.Bot.Simple.BotApp.Internal (BotEnv)
type MyBotApi = BotApi Token
app :: Token -> BotApp model action -> BotEnv model action -> Application
app token botApp botEnv = serveWithContext botApi ctx (server botApp botEnv)
where
ctx = fromToken token :. EmptyContextIf the token is bot123456:ABC, the webhook endpoint generated by BotApi Token is:
POST /bot123456:ABC
The test suite also verifies that token-based routing composes with additional path segments, for example:
GET /bot123456:ABC/info
This module contains small Attoparsec parsers for Telegram slash commands.
Available helpers:
words :: Parser [Text]parses zero or more whitespace-separated wordsbotName :: Parser Textparses a bot mention suffix such as@myBotcommand :: Text -> Parser Textparses a specific slash command like/startcommandArg :: Parser a -> Parser aparses a required argument after at least one spacemCommandArg :: Parser a -> Parser (Maybe a)parses an optional argument after at least one spacecommandWithArg :: Text -> Parser Textparses a named command and returns the remaining text, or""commandWithMArg :: Text -> Parser (Maybe Text)parses a named command and returns the remaining text asMaybeunknownCommand :: Parser Textparses any slash command and returns trailing text, or""unknownCommandWithArgs :: Parser Textparses any slash command and returns trailing text, or""parseTextUpdate :: p -> Parser p -> Text -> pruns a parser with a fallback value on parse failure
{-# LANGUAGE OverloadedStrings #-}
import Prelude hiding (words)
import Data.Attoparsec.Text (Parser)
import Telegram.Bot.Extra.CommandParser
echoParser :: Parser Text
echoParser = commandWithArg "echo"
parseEcho :: Text -> Text
parseEcho = parseTextUpdate "unknown command" echoParserExamples of supported input:
/start
/start@myBot
/echo hello telegram
/echo@myBot payload
/custom some trailing text
This repository currently builds as package telegram-bot-extra version 0.1.0.0.
If you consume it from Git, add the repository as a source dependency and pin the commit you want to use.
Stack example:
extra-deps:
- git: https://github.com/BenefitWizard/telegram-bot-extra
commit: <commit>Library dependencies from the current package definition:
attoparsecbase >= 4.7 && < 5servantservant-clientservant-servertelegram-bot-apitelegram-bot-simpletext
Run the test suite with:
stack testCurrent tests cover:
- token-based route matching for
ForToken - command parsing behavior for all helpers in
Telegram.Bot.Extra.CommandParser
BSD-3-Clause