AWS Lambdaを用いてSlackへの誕生日botを作成する方法

# はじめに
※初のQiita記事ですので、分かりにくい部分等ご容赦ください

コミュニケーションツール、どんなものを使っていらっしゃいますか？
弊社の自社開発チームでは、コミュニケーションツールとして Slack を使用しています。　　

自作の絵文字を使えるなど、便利な機能がたくさんある Slack ですが、
中でも便利なのは、他のツールとの連携がしやすい点ではないでしょうか。

今回はそんな Slack を使い、誕生日の人をお祝いしてくれる誕生日botを
AWS Lambdaを用いて作成した手順をお伝えします。
最終的に、このような派手な見た目で誕生日をお祝いしてくれるbotが作れます。

![誕生日Bot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726324/fbdb88a7-f1dd-b03c-e3b2-72383770a08d.png)

この記事が何かのお役にたてますと幸いです。


# 前提
AWSは既に立ち上がっていると想定しています。
使用するものは以下3つです。
- Incoming Webhook (Slack)
- AWS Lambda
- Amazon EventBridge

# Incoming Webhookの取得
Incoming Webhookは、外部のアプリケーションやサービスがSlackにメッセージを送信するための機能です。
今回はこの機能を使用して得たWebhook URLを使用して、AWSからメッセージを送信します。

### 手順
1. 以下のURLより、Slack APIを開きます。
https://api.slack.com/

2. Your apps より、 Create an App を選択します。既に作成したアプリがある場合、Create New Appという表示に変わります。![create_an_app.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726324/8921c008-ff9a-92a9-c50c-35518844590b.png)

3. From scratch より、Botの命名と使用するワークスペースを選択します。![App作成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726324/ba0bfc73-5942-9db8-2941-742dc4c2205c.png)

4. Basic Information のIncoming Webhooks から、Activate Incoming Webhooks を On にします。![BasicInformation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726324/732fc3c5-992c-dce3-c7ad-e26c0fde59ea.png)

5. 下にスクロールし、Add New Webhook to Workspace から稼働場所を選択し、生成されたURLをコピーします。![add_new_webhook.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726324/1f4a2cd3-484c-4976-41c5-43c0e39a8536.png)

（任意） Basic Informationに戻り、Display Informationからアイコンをカスタマイズします。変更後はSave Changesを忘れずに押してください。![アイコンカスタマイズ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726324/eb147c2f-3d62-ed92-2c4f-84da32ec8f24.png)


これでIncoming Webhookの取得は完了です。




# AWS Lambdaの設定
AWS Lambda は、クラウド上で自動化されたタスクを実行するために用いるものです。
AWS Lambdaでは、AWSの提供するコンピュータリソースを使用してプログラムを実行するため、サーバが必要ありません。

今回は、ここに誕生日の人を判別するコードを記入していきます。

### 手順
1. AWSマネジメントコンソール上で、Lambdaを検索し、関数を作成します。![Lambdaの開始.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726324/d5d80110-4621-2cc0-1b67-620f64191d37.png)

2. 関数名を入力し、関数に使用する言語とロールを設定します。
今回は、birthdayBotという関数名でPythonを使用しました。
ロールは任意のものをお選びください。
![Lambdaの設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726324/4dfb0da0-0bd6-f992-ee06-eb0c163665f0.png)

3. 関数の作成を押し、次に進みます。
4. スクロールして、コードソースを表示し、`lambda_function.py`を開きます。
5. 元々入力されているコードを削除し、以下のコードを貼り付けます。
    ```python
    import json
    import urllib.request
    from datetime import date
    
    # 誕生日リスト
    PEOPLE = {
        ##### <-- 実際の誕生日を入力してください --> #####
        ##### <-- ("氏名", 誕生月, 誕生日) --> #####
        ("佐藤花子", 7, 1),
        ("鈴木一郎", 7, 1),
        ("高橋次郎", 7, 2),
    }
    
    def message(people):
        ##### <-- ここを変更することで任意のメッセージに変えられます --> #####
        return f":confetti_ball::tada::confetti_ball::tada::confetti_ball::tada::confetti_ball::tada::confetti_ball::tada::confetti_ball::tada::confetti_ball::tada:"\
               f"\n\n今日は{people}さんの誕生日です！:birthday:"\
               f"\nおめでとうございます〜〜:raised_hands:"\
               f"\nこの一年が素敵で楽しい日々になりますように:sparkles:"\
               f"\n\n:confetti_ball::tada::confetti_ball::tada::confetti_ball::tada::confetti_ball::tada::confetti_ball::tada::confetti_ball::tada::confetti_ball::tada:"
    
    def post_slack(people):
        send_data = {
            "text": message(people)
        }
        send_text = json.dumps(send_data)
        ##### <-- 先ほどコピーした Webhook URL をペーストしてください --> #####
        url = "https://hooks.slack.com/services/XXXXX/XXXXXXX/XXXXXXXXXX"
        request = urllib.request.Request(
            url, 
            data=send_text.encode('utf-8'), 
            method="POST"
        )
        with urllib.request.urlopen(request) as response:
            response_body = response.read().decode('utf-8')
    
    def get_birthdays_today(people):
        today = date.today()
        birthdays_today = [person for person in people if (person[1] == today.month and person[2] == today.day)]
        return birthdays_today
        
    def lambda_handler(event, context):
        birthdays_today = get_birthdays_today(PEOPLE)
        for person in birthdays_today:
            post_slack(f"{person[0]}")
    ```

6. コード内の誕生日リストと WebHook URL をご自身のものに変更してください。

これで AWS Lambdaの設定は完了です。


# Amazon EventBridgeの設定
Amazon EventBridge は、さまざまなアプリケーションやサービスが発生するイベントを受け取り、そのイベントを別の場所に送ったり、処理したりすることができるサービスです。
今回は、AM 10:00 になったというイベントを元に Lambda を動かすために用います。

この設定が終われば完成です！

### 手順
1. AWSの検索窓から、Amazon EventBridgeを開きます。
2. EventBridge スケジュールを選択し、スケジュールを作成します。![イベントブリッジスケジュール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726324/c5863702-1e6c-40dd-4b15-3cb213db9c05.png)
3. 任意のスケジュール名を入力し、定期的なスケジュールを選択します。
4. cronベースのスケジュールを選択し、 `0 10 * * ? *`を入力します。アスタリスクは全てを表すため、これにより毎日AM 10:00 にスケジュール実行が可能になります。![cron式.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726324/2167597e-dbd6-b55d-50ad-da1949c448f8.png)
5. フレックスタイムをオフに設定し、次に進みます。
6. テンプレート化されたターゲットから、AWS Lambda Invoke を選択します。Lambda Invoke は、特定の Lambda 関数を直接呼び出すことができる API です。![ターゲット選択.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726324/6d7b2b9d-579c-ddc1-18bf-99deb3de0ad9.png)
7. 呼び出すLambda関数を選択し、次に進みます。![呼び出すLambda関数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726324/18880872-a3e2-38c7-509c-44c1a10d7516.png)
8. オプション設定はデフォルトのまま、次に進みます。
9. スケジュールの詳細が意図と同じものになっていることを確認し、スケジュールを作成します。
10. スケジュールから、新しくスケジュールが作成されていることを確認します。![スケジュール確認.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726324/e741e171-b1b1-bd1e-5021-279b40553e2e.png)

これで、Botの作成は完了です！
実際にスケジュールの時間に送られることを確認してください。![誕生日Bot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726324/de3f3e88-2fd6-7239-e3d4-74a8bd7a4e54.png)

# まとめ
今回は、Incoming Webhook 、 AWS Lambda 、Amazon EventBridge を用いてBotの作成をしてみました。
Slack と AWS の連携は、URL を Lambda に貼り付けるだけで比較的容易におこなえました。
また、AWS Lambda と Amazon EventBridge を用いることで自動スケジュール実行も容易にできるので感覚的に用いることができました。
週次のリマインダー等、幅広く活用できそうです。

# 参考記事
https://qiita.com/suo-takefumi/items/b47922362366de897920