File: README.md

package info (click to toggle)
libwww-telegram-botapi-perl 0.12-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 164 kB
  • sloc: perl: 639; makefile: 2
file content (382 lines) | stat: -rw-r--r-- 13,707 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# Name

WWW::Telegram::BotAPI - Perl implementation of the Telegram Bot API

# Synopsis

```perl
use WWW::Telegram::BotAPI;
my $api = WWW::Telegram::BotAPI->new (
    token => 'my_token'
);
# The API methods die when an error occurs.
say $api->getMe->{result}{username};
# ... but error handling is available as well.
my $result = eval { $api->getMe }
    or die 'Got error message: ', $api->parse_error->{msg};
# Uploading files is easier than ever.
$api->sendPhoto ({
    chat_id => 123456,
    photo   => {
        file => '/home/me/cool_pic.png'
    },
    caption => 'Look at my cool photo!'
});
# Complex objects are as easy as writing a Perl object.
$api->sendMessage ({
    chat_id      => 123456,
    # Object: ReplyKeyboardMarkup
    reply_markup => {
        resize_keyboard => \1, # \1 = true when JSONified, \0 = false
        keyboard => [
            # Keyboard: row 1
            [
                # Keyboard: button 1
                'Hello world!',
                # Keyboard: button 2
                {
                    text => 'Give me your phone number!',
                    request_contact => \1
                }
            ]
        ]
    }
});
# Asynchronous request are supported with Mojo::UserAgent.
$api = WWW::Telegram::BotAPI->new (
    token => 'my_token',
    async => 1 # WARNING: may fail if Mojo::UserAgent is not available!
);
$api->sendMessage ({
    chat_id => 123456,
    text    => 'Hello world!'
}, sub {
    my ($ua, $tx) = @_;
    die 'Something bad happened!' if $tx->error;
    say $tx->res->json->{ok} ? 'YAY!' : ':('; # Not production ready!
});
Mojo::IOLoop->start;
```

# Description

This module provides an easy to use interface for the
[Telegram Bot API](https://core.telegram.org/bots/api). It also supports async requests out of the
box using [Mojo::UserAgent](https://metacpan.org/pod/Mojo%3A%3AUserAgent), which makes this module easy to integrate with an existing
[Mojolicious](https://metacpan.org/pod/Mojolicious) application.

# Methods

[WWW::Telegram::BotAPI](https://metacpan.org/pod/WWW%3A%3ATelegram%3A%3ABotAPI) implements the following methods.

## new

```perl
my $api = WWW::Telegram::BotAPI->new (%options);
```

Creates a new [WWW::Telegram::BotAPI](https://metacpan.org/pod/WWW%3A%3ATelegram%3A%3ABotAPI) instance.

**WARNING:** you should only create one instance of this module and reuse it when needed. Calling
`new` each time you run an async request causes unexpected behavior with [Mojo::UserAgent](https://metacpan.org/pod/Mojo%3A%3AUserAgent) and
won't work correctly. See also
[issue #13 on GitHub](https://github.com/Robertof/perl-www-telegram-botapi/issues/13).

`%options` may contain the following:

- `token => 'my_token'`

    The token that will be used to authenticate the bot.

    **This is required! The method will croak if this option is not specified.**

- `api_url => 'https://api.example.com/token/%s/method/%s'`

    A format string that will be used to create the final API URL. The first parameter specifies
    the token, the second one specifies the method.

    Defaults to `https://api.telegram.org/bot%s/%s`.

- `async => 1`

    Enables asynchronous requests.

    **This requires [Mojo::UserAgent](https://metacpan.org/pod/Mojo%3A%3AUserAgent), and the method will croak if it isn't found.**

    Defaults to `0`.

- `force_lwp => 1`

    Forces the usage of [LWP::UserAgent](https://metacpan.org/pod/LWP%3A%3AUserAgent) instead of [Mojo::UserAgent](https://metacpan.org/pod/Mojo%3A%3AUserAgent), even if the latter is
    available.

    By default, the module tries to load [Mojo::UserAgent](https://metacpan.org/pod/Mojo%3A%3AUserAgent), and on failure it uses [LWP::UserAgent](https://metacpan.org/pod/LWP%3A%3AUserAgent).

## AUTOLOAD

```perl
$api->getMe;
$api->sendMessage ({
    chat_id => 123456,
    text    => 'Hello world!'
});
# with async => 1 and the IOLoop already started
$api->setWebhook ({ url => 'https://example.com/webhook' }, sub {
    my ($ua, $tx) = @_;
    die if $tx->error;
    say 'Webhook set!'
});
```

This module makes use of ["Autoloading" in perlsub](https://metacpan.org/pod/perlsub#Autoloading). This means that **every current and future
method of the Telegram Bot API can be used by calling its Perl equivalent**, without requiring an
update of the module.

If you'd like to avoid using `AUTOLOAD`, then you may simply call the ["api\_request"](#api_request) method
specifying the method name as the first argument.

```perl
$api->api_request ('getMe');
```

This is, by the way, the exact thing the `AUTOLOAD` method of this module does.

## api\_request

```perl
# Remember: each of these samples can be aliased with
# $api->methodName ($params).
$api->api_request ('getMe');
$api->api_request ('sendMessage', {
    chat_id => 123456,
    text    => 'Oh, hai'
});
# file upload
$api->api_request ('sendDocument', {
    chat_id  => 123456,
    document => {
        filename => 'dump.txt',
        content  => 'secret stuff'
    }
});
# complex objects are supported natively since v0.04
$api->api_request ('sendMessage', {
    chat_id      => 123456,
    reply_markup => {
        keyboard => [ [ 'Button 1', 'Button 2' ] ]
    }
});
# with async => 1 and the IOLoop already started
$api->api_request ('getMe', sub {
    my ($ua, $tx) = @_;
    die if $tx->error;
    # ...
});
```

This method performs an API request. The first argument must be the method name
([here's a list](https://core.telegram.org/bots/api#available-methods)).

Once the request is completed, the response is decoded using [JSON::MaybeXS](https://metacpan.org/pod/JSON%3A%3AMaybeXS) and then
returned. If [Mojo::UserAgent](https://metacpan.org/pod/Mojo%3A%3AUserAgent) is used as the user-agent, then the response is decoded
automatically using [Mojo::JSON](https://metacpan.org/pod/Mojo%3A%3AJSON).

If the request is not successful or the server tells us something isn't `ok`, then this method
dies with the first available error message (either the error description or the status line).
You can make this method non-fatal using `eval`:

```perl
my $response = eval { $api->api_request ($method, $args) }
    or warn "Request failed with error '$@', but I'm still alive!";
```

Further processing of error messages can be obtained using ["parse\_error"](#parse_error).

Request parameters can be specified using an hash reference. Additionally, complex objects can be
specified like you do in JSON. See the previous examples or the example bot provided in
["SEE ALSO"](#see-also).

File uploads can be specified using an hash reference containing the following mappings:

- `file => '/path/to/file.ext'`

    Path to the file you want to upload.

    Required only if `content` is not specified.

- `filename => 'file_name.ext'`

    An optional filename that will be used instead of the real name of the file.

    Particularly recommended when `content` is specified.

- `content => 'Being a file is cool :-)'`

    The content of the file to send. When using this, `file` must not be specified.

- `AnyCustom => 'Header'`

    Custom headers can be specified as hash mappings.

Upload of multiple files is not supported. See ["tx" in Mojo::UserAgent::Transactor](https://metacpan.org/pod/Mojo%3A%3AUserAgent%3A%3ATransactor#tx) for more
information about file uploads.

To resend files, you don't need to perform a file upload at all. Just pass the ID as a normal
parameter.

```perl
$api->sendPhoto ({
    chat_id => 123456,
    photo   => $photo_id
});
```

When asynchronous requests are enabled, a callback can be specified as an argument.
The arguments passed to the callback are, in order, the user-agent (a [Mojo::UserAgent](https://metacpan.org/pod/Mojo%3A%3AUserAgent) object)
and the response (a [Mojo::Transaction::HTTP](https://metacpan.org/pod/Mojo%3A%3ATransaction%3A%3AHTTP) object). More information can be found in the
documentation of [Mojo::UserAgent](https://metacpan.org/pod/Mojo%3A%3AUserAgent) and [Mojo::Transaction::HTTP](https://metacpan.org/pod/Mojo%3A%3ATransaction%3A%3AHTTP).

**NOTE:** ensure that the event loop [Mojo::IOLoop](https://metacpan.org/pod/Mojo%3A%3AIOLoop) is started when using asynchronous requests.
This is not needed when using this module inside a [Mojolicious](https://metacpan.org/pod/Mojolicious) app.

The order of the arguments, except of the first one, does not matter:

```perl
$api->api_request ('sendMessage', $parameters, $callback);
$api->api_request ('sendMessage', $callback, $parameters); # same thing!
```

## parse\_error

```perl
unless (eval { $api->doSomething(...) }) {
    my $error = $api->parse_error;
    die "Unknown error: $error->{msg}" if $error->{type} eq 'unknown';
    # Handle error gracefully using "type", "msg" and "code" (optional)
}
# Or, use it with a custom error message.
my $error = $api->parse_error ($message);
```

When sandboxing calls to [WWW::Telegram::BotAPI](https://metacpan.org/pod/WWW%3A%3ATelegram%3A%3ABotAPI) methods using `eval`, it is useful to parse
error messages using this method.

**WARNING:** up until version 0.09, this method incorrectly stopped at the first occurence of `at`
in error messages, producing results such as `missing ch` instead of `missing chat`.

This method accepts an error message as its first argument, otherwise `$@` is used.

An hash reference containing the following elements is returned:

- `type => unknown|agent|api`

    The source of the error.

    `api` specifies an error originating from Telegram's BotAPI. When `type` is `api`, the key
    `code` is guaranteed to exist.

    `agent` specifies an error originating from this module's user-agent. This may indicate a network
    issue, a non-200 HTTP response code or any error not related to the API.

    `unknown` specifies an error with no known source.

- `msg => ...`

    The error message.

- `code => ...`

    The error code. **This key only exists when `type` is `api`**.

## agent

```perl
my $user_agent = $api->agent;
```

Returns the instance of the user-agent used by the module. You can determine if the module is using
[LWP::UserAgent](https://metacpan.org/pod/LWP%3A%3AUserAgent) or [Mojo::UserAgent](https://metacpan.org/pod/Mojo%3A%3AUserAgent) by using `isa`:

```perl
my $is_lwp = $user_agent->isa ('LWP::UserAgent');
```

### Using a proxy

Since all the painful networking stuff is delegated to one of the two supported user agents
(either [LWP::UserAgent](https://metacpan.org/pod/LWP%3A%3AUserAgent) or [Mojo::UserAgent](https://metacpan.org/pod/Mojo%3A%3AUserAgent)), you can use their built-in support for proxies
by accessing the user agent object. An example of how this may look like is the following:

```perl
my $user_agent = $api->agent;
if ($user_agent->isa ('LWP::UserAgent')) {
  # Use LWP::Protocol::connect (for https)
  $user_agent->proxy ('https', '...');
  # Or if you prefer, load proxy settings from the environment.
  # $user_agent->env_proxy;
} else {
  # Mojo::UserAgent (builtin)
  $user_agent->proxy->https ('...');
  # Or if you prefer, load proxy settings from the environment.
  # $user_agent->detect;
}
```

**NOTE:** Unfortunately, [Mojo::UserAgent](https://metacpan.org/pod/Mojo%3A%3AUserAgent) returns an opaque `Proxy connection failed` when
something goes wrong with the `CONNECT` request made to the proxy. To alleviate this, since
version 0.12, this module prints the real reason of failure in debug mode. See ["DEBUGGING"](#debugging).
If you need to access the real error reason in your code, please see
[issue #29 on GitHub](https://github.com/Robertof/perl-www-telegram-botapi/issues/29).

# Debugging

To perform some cool troubleshooting, you can set the environment variable `TELEGRAM_BOTAPI_DEBUG`
to a true value:

```perl
TELEGRAM_BOTAPI_DEBUG=1 perl script.pl
```

This dumps the content of each request and response in a friendly, human-readable way.
It also prints the version and the configuration of the module. As a security measure, the bot's
token is automatically removed from the output of the dump.

Since version 0.12, enabling this flag also gives more details when a proxy connection fails.

**WARNING:** using this option along with an old Mojolicious version (< 6.22) leads to a warning,
and forces [LWP::UserAgent](https://metacpan.org/pod/LWP%3A%3AUserAgent) instead of [Mojo::UserAgent](https://metacpan.org/pod/Mojo%3A%3AUserAgent). This is because [Mojo::JSON](https://metacpan.org/pod/Mojo%3A%3AJSON)
used incompatible boolean values up to version 6.21, which led to an horrible death of
[JSON::MaybeXS](https://metacpan.org/pod/JSON%3A%3AMaybeXS) when serializing the data.

# Caveats

When asynchronous mode is enabled, no error handling is performed. You have to do it by
yourself as shown in the ["SYNOPSIS"](#synopsis).

# See also

[LWP::UserAgent](https://metacpan.org/pod/LWP%3A%3AUserAgent), [Mojo::UserAgent](https://metacpan.org/pod/Mojo%3A%3AUserAgent),
[https://core.telegram.org/bots/api](https://core.telegram.org/bots/api), [https://core.telegram.org/bots](https://core.telegram.org/bots),
[example implementation of a Telegram bot](https://git.io/vlOK0),
[example implementation of an async Telegram bot](https://git.io/vDrwL)

# Author

Roberto Frenna (robertof AT cpan DOT org)

# Bugs

Please report any bugs or feature requests to
[https://github.com/Robertof/perl-www-telegram-botapi](https://github.com/Robertof/perl-www-telegram-botapi).

# Thanks

Thanks to [the authors of Mojolicious](https://metacpan.org/pod/Mojolicious) for inspiration about the license and the
documentation.

# License

Copyright (C) 2015, Roberto Frenna.

This program is free software, you can redistribute it and/or modify it under the terms of the
Artistic License version 2.0.