Telegram botをAWS Lambdaでやってみた

Leoです。
この記事は [Wanoグループ Advent Calendar 2019](https://qiita.com/advent-calendar/2019/wano-group) の22日目の記事になります。

[Telegram](https://telegram.org/)のアプリにserverless botの機能を追加しました。
現在僕は複数のメッセンジャを使っています。
Lineにはbotを[簡単に追加できますが](https://dev.classmethod.jp/etc/lambda-line-bot-tutorial/)、今回初めてTelegramのアプリに入れる必要があったので、この記事をメモとしても書きました。

### Telegramのbotの実装には基本的に４ステップがあります。
1. Botの登録
2. AWS lambdaの登録
3. AWS API Gatewayのendpointを追加
4. EndpointをTelegramにwebhookとして登録

## Botの登録
Lineと違って、Telegramのbot登録やbotの操作はアプリ内でできます。（Lineの場合、Developerのページでやります）

TelegramのアプリにBotFatherっていうアカウントを検索します。

screen![screenshot_20191222-223346__02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529952/c0fd769e-7d08-fe69-261d-fcbcc8603afc.jpeg)

BotFatherとのチャットに'/newbot'のコマンドで新しいbotを登録します。
登録が始まったら、botの名前とかuser_idを登録します。

![screenshot_20191222-223327__01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529952/43320d90-5efa-76cf-b99c-8db60cdf8739.jpeg)


登録は完了したらbotのAPIにアクセスする時に必要なtokenが発行されます。secret tokenのため、安全なストレージに保存しましょう。
このチャットでbotの設定の更新もできます。

## Lambdaの登録

Lambdaを登録します。今日はAWSのコンソールでの登録を説明します。
今回http requestしか使わないのでデフォルトのNodejs環境で実装しますが、GoやPythonなどの環境でも簡単に実装できます。
<img width="2421" alt="Screen Shot 2019-12-22 at 22.55.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529952/7c446d8a-8d9c-7283-1768-6fc75e734151.png">
Lambdaの中に以下のことをやっています。
1. Webhookのイベントを受け取っている
2. Webhookのリクエストのパラメータからmessageのtextを取得している
3. TelegramのAPIを叩いてチャネルに返信してる

上の３つの機能が含まれている以下のコードをLambdaのindex.jsに入れる。

```
const https = require('https');

const BOT_TOKEN = process.env.BOT_TOKEN
const URL = "https://api.telegram.org/bot" + BOT_TOKEN + "/sendMessage?";

exports.handler = function(event, context, callback) {
    
    let text = 'Echo: ' + event.message.text;
    let chatId = event.message.chat.id;
    let replyUrl = URL + 'text=' + text + '&chat_id=' + chatId;
    
    https.get(replyUrl, (res) => {
        console.log("Got response: " + res.statusCode); 
        callback(null, res.statusCode)
      }).on('error', (e) => {
        console.log("Got error: " + e.message); 
        callback(Error(e))
      })
};
```
Telegramのチャネルにメッセージの送信は単純なGETでできます。
LambdaのEnvironment variableにBOT_TOKENを定義する必要があります。

最後に'保存'押して、Lambdaの登録は完了です。

## APIの登録

BotのWebhookになるAWS API GatewayのREST APIを登録します。

<img width="728" alt="1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529952/7c8a3c98-0a65-51f3-0942-fcea98b56a76.png">

新しいAPIを登録します。
<img width="901" alt="2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529952/17b8d7a4-af34-980c-9b11-2fd6a505bd71.png">

Resource/PathをCreate Resourceで指定します。
<img width="580" alt="3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529952/63dab568-3d9a-918d-74cd-6c81db8386aa.png">

<img width="1150" alt="4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529952/1fe77b13-5cfb-6ab7-7a3d-89735520c36c.png">

TelegramのWebhookはPOSTで通知するので、Create MethodでPOST指定します。
<img width="589" alt="5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529952/eab93edf-05d9-a8bb-c066-92007feb7c7e.png">
<img width="450" alt="6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529952/cab6bee1-b3fe-4cbc-ed73-22478737db49.png">

HTTP Methodを指定したら、APIと前に登録したLambdaを結びつくためにIntegrationに用意したLambda名を入れます。そうするとこのAPIはトリガーとして登録されます。
<img width="1046" alt="7.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529952/2701efb9-b8fe-0a3f-d3a1-dc8b2c05b618.png">

後はステージ名を振ってAPIをデプロイするだけです。
<img width="571" alt="8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529952/4ede5352-a599-ac3f-66fd-736c5058b05c.png">

今回はステージ名を'test'にしました。
<img width="604" alt="9.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529952/add2caf9-0ca8-0863-742a-8cc7e30f2a26.png">

APIをデプロイしたらページの上に'Invoke API URL'が以下のように表示されます。

```
https://fiXXXX1oe.execute-api.us-east-2.amazonaws.com/test/
```
これはまだWebhookのURLではありません。最後の'test'はステージ名になります。
このURLの後ろにAPIのpath（今回は'bot-test'）を付けるとWebhookのURLになります。

```
https://fiXXXX1oe.execute-api.us-east-2.amazonaws.com/test/bot-test
```

## Webhookの登録

最後にAPI Gatewayに登録したURLをTelegramにWebhookとして登録しましょう。
そのために以下のTelegramのAPIを使えます。

```
https://api.telegram.org/bot<BOT_TOKEN>/setWebHook?url=<WEBHOOK_URL>
```

<>のところをそれぞれ入れてGETリクエストを叩きます（ブラウザからでもOK）

```
https://api.telegram.org/bot1001745750:AAFDXkXXXXXXXXXXXXXXXXXXX4kqp0Mto/setWebHook?url=https://fiXXXX1oe.execute-api.us-east-2.amazonaws.com/test/bot-test
```

以下の返信が来ます。

```
{"ok":true,"result":true,"description":"Webhook was set"}
```


これでBotの基本的な実装は終わりです。
Telegramでbotを検索して、チャネルに書いてみるとEchoされます。
![10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529952/1b82cd43-66d3-6ce7-41d7-f32d257793ca.jpeg)

##　終わりに

もちろんこのbotは例として作りました。LambdaがトリガとしてAWSの色々なサービスに広げることもできます。DBにアクセスやSFNをキックすることなどできます。

Lineのbotと比べてTelegramのbotのAPIはシンプルで、serverlessなbotは誰も作れるって感じでした。