プログラミング初心者が Python で Slack bot 作成 [ 本番編 ]

## はじめに

[プログラミング初心者が Python で Slack bot 作成 [ 実践編 ]](https://qiita.com/fruity/items/48b1e09e51aa01bf199d) の続きとなります。
前回作成したものを AWS Lambda にデプロイ ( 本番環境で使えるようにすること ) していきます。
Lambda の設定が終わっていない方は [こちら](https://aws.amazon.com/jp/register-flow/) を参考にアカウントの作成をしてください。

## 開発環境

### 環境

- Python
- Docker
- Make

### ツール

- Atom Editor
- iTerm 2

## 本番環境

- AWS Lambda

## 実践

### IAM ロールの作成

ロールとは、複数の権限をひとまとめにしたもののことをいいます。
複数人で開発する際、誰に対してどの程度の権限を与えるかを設定するものになります。

まずは AWS にログインし、トップページの __AWS のサービス__ から __IAM__ を検索してください。

<img width="809" alt="スクリーンショット 2019-04-10 15.05.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/e5c80a73-c352-44ff-3503-f54de0acb816.png">


左側の __ロール__ から __ロールの作成__ をクリックしてください。

<img width="1440" alt="スクリーンショット 2019-04-10 15.10.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/f69ad6da-17b9-e634-613f-cc65d0ad1343.png">

__このロールを使用するサービスを選択__ で __Lambda__ を選択して、 __次のステップ : アクセス権限__ をクリックします。

<img width="1440" alt="スクリーンショット 2019-04-02 16.04.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/a1c31164-78b3-78c7-c7b6-0716ff0cdd2f.png">

特にアクセス権限は必要ないので、そのまま __次のステップ : タグ__ をクリックします。

<img width="1440" alt="スクリーンショット 2019-04-10 15.14.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/8e04e2ae-d639-fe16-517e-b81519b14825.png">

タグの追加も必要ないので、そのまま __次のステップ : 確認__ をクリックします。

<img width="1440" alt="スクリーンショット 2019-04-10 15.16.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/0944476c-3e20-d4c6-7892-2424e4b310c8.png">

最後に任意のロール名を付けて __ロールの作成__ をクリックして完了です！

<img width="1440" alt="スクリーンショット 2019-03-24 21.29.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/1a499549-2d19-e407-8478-55c96f6098f4.png">

### 関数の作成

続いて実際にプログラムを動かす設定を行います。

トップページの __AWS のサービス__ から __Lambda__ を検索してください。

<img width="808" alt="スクリーンショット 2019-04-10 15.29.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/50bf0603-c742-38d2-9343-42093396fb48.png">


続いて右上の __関数の作成__ をクリックしてください。

<img width="1099" alt="スクリーンショット 2019-04-02 15.07.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/caa7097b-029b-3795-b0b8-2abc20288d62.png">

ここで Lambda で実行したいプログラムを登録することができます。
具体的なプログラムの設定を行います。


<img width="1440" alt="スクリーンショット 2019-04-02 15.19.48(1).png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/cadba6a8-8e59-e479-d6fd-d05f7ac642b2.png">

- __一から作成__ を選択してください。
- __基本的な情報__ の __関数名__ は皆さんの自由で大丈夫です ( 降水強度の通知をしたいので rainfall_notification にしました ) 。
- __ランタイム__ は実行する言語を選択するので __Python 3.6__ にします。
- __アクセス権限__ の __実行ロール__ は __既存のロールを使用する__ を選択します。
- __既存のロール__ で先程作成したロールを選択してください。

右下の __関数の作成__ をクリックすると、次のような画面に移ります。

<img width="1440" alt="スクリーンショット 2019-04-04 22.24.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/d5723063-6dfa-6ef4-9127-5dc5dab3b6bd.png">

まずはトリガーの設定を行います。
左側の __トリガーの追加__ から、 __CloudWatch Events__ を選択してください。
これで設定した時間にプログラムを発火させることができます。
では画面下にある __トリガーの設定__ を説明していきます。

<img width="1279" alt="スクリーンショット 2019-04-04 23.05.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/be51d8a3-afee-663a-813e-0688e41a4353.png">

- __ルール__ は __新規ルールの作成__ を選択してください。
- __ルール名__ は皆さんの自由で大丈夫です。
- __ルールの説明__ は特に記入するする必要はありません。
- __ルールタイプ__ は __スケジュール式__ を選択してください。
- __スケジュール式__ は cron を使用して設定していきます。 cron については[こちら](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/tutorial-scheduled-events-schedule-expressions.html)を参考にしてください。今回は 1 日に 4 回 ( 6時間に 1 回 ) 通知したいので __cron(0 0/6 * * ? *)__ とします ( ただしこれは日本標準時ではなく、協定世界時なので注意してください ) 。
- __トリガーの有効化__ にチェックを入れてください。

以上の設定が終わったら右下の __追加__ をクリックしてください。

続いて関数の設定を行います。
先程設定した __CloudWatch Events__ の右上の __rainfall_notification__ をクリックしてください。

<img width="1279" alt="スクリーンショット 2019-04-04 22.29.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/5895c7ce-e05d-13be-d193-ae7ca6f1e1f4.png">


画面下の __関数コード__ に作成したプログラムを書き込みます。
すでに記載してあるコードの下に追記してください。。

<img width="1279" alt="スクリーンショット 2019-04-05 12.45.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/17a26259-66c4-f10f-a9d5-a784bc44005b.png">

まず `urllib` をインポートしましょう。

```py:lambda_function
import json
import urllib.request # 追記

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }
```

次に新たに関数を定義します ( 関数名は任意で ) 。

```py:lambda_function
import json
import urllib.request

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

def rainfall_notification(): # 追記
	
```

では定義した関数の中に作成したプログラムをまるっと移しましょう。

```py:lambda_function
import json
import urllib.request

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

def rainfall_notification():
	REQUEST_URL = '作成したリクエスト URL'

	WEB_HOOK_URL = '取得した Web hook URL'

	reqg = urllib.request.Request(REQUEST_URL)
	    with urllib.request.urlopen(reqg) as res:
	        response = res.read()

	response = response.decode()

	d = json.loads(response)

	rainfall = d['Feature'][0]['Property']['WeatherList']['Weather'][0]['Rainfall']

	payload_d = {
	    'text': '現在の赤羽駅の降水強度は {} mm/h です。'.format(rainfall)
	}

	data = json.dumps(payload_d).encode('utf-8')

	reqp = urllib.request.Request(WEB_HOOK_URL, data, method='POST')
	with urllib.request.urlopen(reqp) as res:
		body = res.read().decode('utf-8')
	
```

ここで注意しなければいけないのが、 Python はインデント ( 段落 ) で関数の終わりを判断しているので、必ず `def weather_notification` の中に入るように書き込んでください。

では続いて発火するように設定してみましょう。

```py:lambda_function
import json
import urllib.request

def lambda_handler(event, context):
    # TODO implement
    rainfall_notification() # 追記
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

def rainfall_notification():
	REQUEST_URL = '作成したリクエスト URL'

	WEB_HOOK_URL = '取得した Web hook URL'

	reqg = urllib.request.Request(REQUEST_URL)
	    with urllib.request.urlopen(reqg) as res:
	        response = res.read()

	response = response.decode()

	d = json.loads(response)

	rainfall = d['Feature'][0]['Property']['WeatherList']['Weather'][0]['Rainfall']

	payload_d = {
	    'text': '現在の赤羽駅の降水強度は {} mm/h です。'.format(rainfall)
	}

	data = json.dumps(payload_d).encode('utf-8')

	reqp = urllib.request.Request(WEB_HOOK_URL, data, method='POST')
	with urllib.request.urlopen(reqp) as res:
		body = res.read().decode('utf-8')
	
```

`# TODO implement` と `return` の間に定義した関数を追記してください。

以上で関数の作成は完了です！
右上の __保存__ をクリックして保存してください。

<img width="1440" alt="スクリーンショット 2019-04-10 17.43.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/b603706c-c5ba-9cb8-65b8-348414216487.png">

### テスト

ではテストをしてみましょう。
右上の __テストイベントの選択__ から __テストイベントの設定__ を選択してください。

<img width="827" alt="スクリーンショット 2019-04-10 17.53.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/3c90de76-7595-d5e3-269e-dc7a7fcd6195.png">

<img width="821" alt="スクリーンショット 2019-04-05 14.14.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/5a2ed3bb-67f8-f8f9-e508-c7e556a97c95.png">

__イベント名__ に任意の名前をつけてください。
それ以外は特に何も設定する必要はないので、そのまま __作成__ をクリックしてください。

では実際にテストしてみましょう。
先程作成したテストイベントを選択して、 __テスト__ をクリックしてください。

<img width="809" alt="スクリーンショット 2019-04-05 14.20.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/3a090d63-a10b-e97b-4fe3-dfa2046f5cf0.png">

Slack に通知が来れば成功です！

<img width="335" alt="スクリーンショット 2019-04-05 15.21.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/371718/cd446aac-70c4-5dca-0859-a8692ca69e17.png">

## 最後に

とても長くなってしまいましたが、いかがだったでしょうか？
今回はエラー処理 ( リクエストが帰ってこなかったときの処理 ) は実装しなかったので、次に Bot を作るときに実装したいと思います。