この記事は 『CRESCO Advent Calendar 2017』 13日目の記事です。
こんにちは。技術研究所の910です。
もう旬が過ぎてしまった感じもしますが、Chaliceを利用してSlackへのWebhookを投げるWebAPIを以前作ったので、そのときのことを備忘録として残します。
- Slack
- AWS Chalice
- ChaliceからSlackにメッセージを投げる
- Slack Incoming Webhook APIの作成
- PythonからSlackにメッセージを投げる
- 汎用ライブラリを利用する方法(requests)
- slackweb
最早Slackについて説明する必要は無いと思いますが、敢えて言うならば
- 公開されているプラグインを導入して好きなように拡張できる
- Webhookを受けられる
という特徴を持ったチャットツールと言えると思います。
一言で言うとFlaskライクに書けて、簡単にLambdaとAPI GatewayにデプロイできるPython用のサーバレスフレームワークです。
導入方法や使い方、実装例はすべてChaliceのGitHubにまとめられているので、そちらをご参照ください。
ちなみに、私が利用したChaliceのバージョンは1.0.4になります。
Chaliceは、LambdaがサポートするPythonのバージョンのみをサポートしています。
対応していないバージョンのPythonで利用しようとすると、以下のようなエラーが出て使えません。
Note: make sure you are using python2.7 or python3.6.
The chalice CLI as well as the chalice python package will support the versions of python supported by AWS Lambda.
Currently, AWS Lambda supports python2.7 and python3.6, so that's what this project supports.
Chaliceに限らず、特定のバージョンのPythonでしか動かないライブラリは多々あるので、用途毎に仮想環境を作れるようにしておくと何かと便利です。
仮想環境を扱う手段としては以下のようなものがあります。
これらの違いについては、以下のページをご参照ください。
前置きが長くなりましたが、ようやくここからが本題です。
Chaliceを使って、SlackにWebhookを投げる迄の流れを記載していきます。
- Workspaceを作っていない場合はこちらを参考に、Workspaceを作成してください。
- Slack APIにアクセスし、Start Buildingを選択します。
- 1にて用意したWorkspaceを選択し、Create Appを選択します。
- Incoming Webhooksを選択します。
- Activate Incoming WebhookをONにします。
- Activate Incoming WebhookをONにするとWebhook URLs for Your Workspaceという項目が画面下部に表示されます。
この中のAdd New Webhook to Workspaceを選択します。
-
ここでWorkspaceのどのチャネルに対してメッセージを投げるのかを指定します。
Post toにメッセージを投げたいチャネルを指定してAuthorizeを選択すると、Webhookを投げる為に使うURLと、メッセージを投げる為のcurlコマンドが表示されます。試しにこのcurlコマンドをターミナルで叩くと、指定されたチャネルに対してメッセージが投げられます。
ようやくここからが実装の部分になります。
PythonからSlackにメッセージを投げる手段としては、大きく分けて2つあります。
まずは汎用的なHTTPライブラリを使い、POSTリクエストを投げる方法です。
Python 3にはurllib.requestが標準搭載されていますが、ここではよりシンプルに実装できるrequestsを使っています。
requestsはpip install requests
でインストールできます。
ちなみに、curlコマンドを見る限りではSlackにメッセージを投げる為にはWebhook URLとメッセージの文面があれば良いので、ソースコードは非常にコンパクトになります。
# ----- to_slack_with_requests.py ----- # |
import json |
import requests |
WEBHOOK_URL = "YOUR_WEBHOOK_URL" |
def to_slack(text: str): |
# curlで投げたデータと同じ形のデータを用意 |
payload = json.dumps({'text': text}) |
res = requests.post(WEBHOOK_URL, data=payload) |
もう一つの方法は、slackwebというSlack専用のライブラリを使う方法です。
requestsと同様、pip install slackweb
でインストールできます。
流石にSlack専用のライブラリだけあって、requestsを使う場合よりも更にコンパクトなソースコードになりました。
# ----- to_slack_with_slackweb.py ----- # |
import slackweb |
WEBHOOK_URL = "YOUR_WEBHOOK_URL" |
slack = slackweb.Slack(url=WEBHOOK_URL) |
def to_slack(text: str): |
slack.notify(text=text) |
こちらもto_slack("Slackwebからきました。")
を実行して、Slackにメッセージが投げられるのを確認できました。
このように、僅か数行のスクリプトで簡単にSlackにメッセージを投げられるということが分かるかと思います。
ようやくここからChaliceを使っていきます。
いきなりデプロイするのは怖いので、とりあえずはローカルでChaliceを動かしてSlackにメッセージを投げてみます。
また、先程はrequests
とslackweb
を使う2つの方法を示しましたが、以降はslackweb
を利用したスクリプトを使います。
Chaliceもrequestsなどと同様、pip install chalice
で導入できます。
また、Chaliceの導入と同時にchalice
コマンドにPATHが通されます。
chalice
コマンドで使えるオプションはいくつかあるのですが、今回は以下の3つしか使いません。
オプションを全てチェックしたいときはchalice --help
で確認してみてください。
また、この作業ではChalice Python Serverless Microframework for AWS 1.0.4 documentationを参照しました。
機能 | 概要 |
---|---|
deploy | ChaliceのプロジェクトをLambda、API Gatewayにデプロイする |
local | Chaliceのプロジェクトをlocalhostで実行する |
new-project | 新規プロジェクトを作成する |
- 新規プロジェクトの作成
chalice new-projectコマンドを任意のディレクトリで実行すると、最小限の構成のディレクトリが生成されます。
# Chaliceの新規プロジェクトを作成 |
(chalice)$ chalice new-project hook_to_slack |
# 新規プロジェクトの構造 |
# ※ treeコマンドは brew install tree で導入できる(macOSの場合) |
(chalice)$ tree hook_to_slack/ |
hook_to_slack/ |
├── app.py |
└── requirements.txt |
Chaliceを利用する場合、指定されたディレクトリに手持ちのスクリプトやライブラリのファイルを配置しておくことでそれらのライブラリを利用することができます。
その為、既存のモジュールを再利用したり、適宜モジュール分割したりといったことができます。
ディレクトリ構成のルールはこちらにあるので、適宜ご参照ください。
先程実装したto_slack_with_slackweb.py
とslackweb
ライブラリを配置して、最終的にはこのようなディレクトリ構成になりました。
(chalice)$ tree hook_to_slack/ |
hook_to_slack/ |
├── app.py |
├── chalicelib # 手持ちのモジュールを入れるトコ |
│ └── to_slack_with_requests.py |
├── requirements.txt # サードパーティ製のライブラリの一覧 |
└── vendor # pipで取得したサードパーティ製のライブラリを入れるトコ |
└── slackweb-1.0.5-py3-none-any.whl |
また、Pythonを使っている方ならばお馴染みのrequirements.txtも用意する必要があります。
以下のように、サードパーティ製のライブラリの名称を記載して配置してください。
今回はslackweb
が必要なので、このような内容のrequirements.txtを用意しました。
# ----- requirements.txtの記載例 ----- # |
slackweb==1.0.5 |
pip downloadで取得したファイルの形式がwhl形式でない場合、デプロイする際にはwhl形式に変換する必要があります。
以下の流れで変換してからvendorディレクトリに配置してください。
# ----- ライブラリのダウンロード 〜 whl形式への変換迄の流れ ----- # |
# wheelが入っていない場合は入れる |
(chalice)$ pip install wheel |
(chalice)$ cd vendor |
(chalice)$ pip download slackweb # 使いたいライブラリをダウンロード |
Collecting slackweb Using cached slackweb-1.0.5.tar.gz |
Saved ./slackweb-1.0.5.tar.gz |
Successfully downloaded slackweb |
(chalice)$ pip wheel slackweb-1.0.5.tar.gz # whl形式に変換 |
Processing ./slackweb-1.0.5.tar.gz |
Building wheels for collected packages: slackweb |
Running setup.py bdist_wheel for slackweb ... done |
Stored in directory: /Users/user/hook_to_slack/vendor |
Successfully built slackweb |
(chalice)$ ls -al |
total 16 |
drwxr-xr-x 4 user staff 128 Nov 10 14:39 . |
drwxr-xr-x 9 user staff 288 Nov 10 14:39 .. |
-rw-r--r-- 1 user staff 2617 Nov 10 14:39 slackweb-1.0.5-py3-none-any.whl |
-rw-r--r-- 1 user staff 1337 Nov 10 14:39 slackweb-1.0.5.tar.gz |
(chalice)$ rm slackweb-1.0.5.tar.gz # 要らない方は消す |
リファレンスにはもっと詳細な説明がありますので、もしサードパーティ製ライブラリに起因する問題が発生した場合にはこちらを参照してみてください。
app.pyにリクエストを受けたときの処理を実装します。
既にSlackに対してPOSTリクエストを投げる部分は実装済みですので、その関数を呼び出すだけで済みます。
また、書き方はFlaskとそっくりなので、非常に書き易いかと思います。
(スクリプトのファイル名が冗長ですが、ここでは眼をつむってください…)
from chalice import Chalice |
from chalicelib.to_slack_with_slackweb import to_slack |
app = Chalice(app_name="post2slack") |
app.debug = True |
@app.route('/toslack', methods=['POST']) |
def index(): |
text = app.current_request.json_body["text"] |
to_slack(text) |
- Chaliceをローカルで動かして動作確認
ここ迄終わったらchalice localを実行して動作確認をします。
これで問題なくメッセージが投げられれば、後はデプロイするだけです。
# Chaliceをローカルで実行 |
(chalice)$ chalice local |
Serving on localhost:8000 |
# 別のターミナルからcurlを叩く |
(chalice)$ curl -v -H "Content-Type: application/json" -d '{"text":"chaliceからきました"}' localhost:8000/toslack |
* Trying 127.0.0.1... |
* TCP_NODELAY set |
* Connected to localhost (127.0.0.1) port 8000 (#0) |
POST /toslack HTTP/1.1 |
Host: localhost:8000 |
User-Agent: curl/7.54.0 |
Accept: */* |
Content-Type: application/json |
Content-Length: 36 |
* upload completely sent off: 36 out of 36 bytes |
HTTP/1.1 200 OK |
Server: BaseHTTP/0.6 Python/3.6.3 |
Date: Fri, 10 Nov 2017 06:16:43 GMT |
Content-Length: 4 |
Content-Type: application/json |
* Connection #0 to host localhost left intact |
問題がなければこのように、メッセージが投げられるはずです。
デプロイを行う為には認証情報が必要となりますので、予めAWS CLIのセットアップを済ませておいてください。
CLIのセットアップが終わっていれば、deploy
コマンドを叩くだけでデプロイされます。
(chalice)$ chalice deploy |
Creating role: hook_to_slack-dev |
Creating deployment package. |
Creating lambda function: hook_to_slack-dev |
Initiating first time deployment. |
Deploying to API Gateway stage: api |
https://@@@@@@@@@@@@@@@@@@@@.execute-api.ap-northeast-1.amazonaws.com/api/ |
chalice deploy
すると、最後にURLが表示されます。
このURLを使ってAPIの呼び出しを行いますので、このURLを控えておいてください。
2017年11月現在では、Lambdaには合計50MB迄アップロードできます。
TensorFlowを入れたプロジェクトをchalice deployしようとしたら、Lambdaのファイル容量の制限に引っ掛かってしまいデプロイすることができませんでした…
正直、拍子抜けするくらい簡単にWebAPIが作れてびっくりしました。
ちなみにLINE BOTでもWebhookを受けられるので、ChaliceでBOTを拡張していくのも楽しそうだなーと思っています。