実現したいこと
chatworkの無料アカウントだと過去のメッセージが閲覧できなくなってしまったので、
閲覧期限が過ぎたメッセージを見返すために都度メッセージを記録する処理を作りたい。
はじめに
復習を兼ねて記事にしました。
スプレッドシートウェブアプリとlambdaを併用する意味はあまりないと思います。
lambdaを使いたくなったというのと最初はメッセージの保存先をスプレッドシートにするつもりがなかったので、
結局この形になってしまいました。
特にこだわりがなければスプレッドシートウェブアプリをwebhook urlとして使った方が早いかもしれません。
環境
chatwork webhook
AWS Lambda
AWS API Gateway
python 3.9
Googleスプレッドシート
GAS
Windows 11
実行手順
1 スプレッドシートウェブアプリの作成
[1] GASプロジェクトに以下コードを転記
function doPost(e) {
const post = e.postData.contents
const sheet = SpreadsheetApp.getActiveSheet();
const postObj = JSON.parse(post)
const webhook_event = postObj["webhook_event"]
insertWebhookEvent(sheet, webhook_event)
}
// 対象シートの最終行にwebhook_eventの内容をそのまま転記する関数
// sheet:対象シート webhook_event:chatwork_webhookのbody["webhook_event"]
const insertWebhookEvent = (sheet, webhook_event) => {
const keys = Object.keys(webhook_event)
const insertAry2d = keys.map((key) => {
if (key === "send_time") {
const sendDateJst = Utilities.formatDate(new Date(webhook_event[key] * 1000), "JST", "yyyy/MM/dd HH:mm:ss");
return sendDateJst
}
return webhook_event[key]
})
sheet.appendRow(insertAry2d)
}
[2] デプロイする
右上のデプロイをクリック
-> 新しいデプロイ
-> ウェブアプリを選択
-> 適当な名称を付ける(アクセスできるユーザーは全員)
-> URLをメモ
2 webhookの編集
[1] webhookの新規作成
※この時のURLはとりあえず、メモしたスプレッドシートウェブアプリのURLを入力
[2] 作成したwebhookのトークンをメモ
※新規作成後、webhook設定IDの下にあります。
3 lambda関数の作成
[1] aws lambdaを開く
AWS Lambda
-> 関数
-> 関数の作成をクリック
[2] lambdaの基本情報の入力
一から作成
-> 基本的な情報を入力
-> 右下、関数の作成をクリック
[3] webhookからリクエストを受け、スプレッドシートウェブアプリにpostする関数の作成
コードソース -> lambda_functionに以下の内容を転記
import os
import base64
import hashlib
import hmac
import json
import requests
def lambda_handler(event, context):
# webhook編集画面のtoken
token = os.environ["CHATWORK_API_TOKEN"]
# リクエストヘッダー内の署名検証に使うための署名文字列
request_signature = event["headers"]["x-chatworkwebhooksignature"]
request_body = event["body"]
digest = hmac.new(base64.b64decode(token), request_body.encode("utf-8"), hashlib.sha256).hexdigest()
expected_signature = base64.b64encode(bytes.fromhex(digest)).decode("utf-8")
# 署名確認
if not(request_signature == expected_signature):
print("署名エラー")
return {
"statusCode": 410,
"body": "SignatureDoesNotMatch"
}
url = os.environ["SPREADSHEET_URL"]
json_item = json.dumps(event)
j = json.loads(json_item)
webhook_body = j["body"]
requests.post(url, data=webhook_body.encode("utf-8"))
return {
"statusCode": 200
}
🖊上記のコードの内容
json_itemまででリクエストされた値の署名検証行っている
署名検証で許可された場合、スプレッドシートウェブアプリにpostリクエストを行う
スプレッドシートウェブアプリとwebhook編集画面のtokenは環境変数から取得する
[4] 環境変数の設定
関数作成画面中央部、設定をクリック
-> 左一覧から環境変数をクリック
-> 編集をクリック
-> キー、値に以下を入力し1個ずつ作成し保存
キー | 値 |
---|---|
SPREADSHEET_URL | スプレッドシートウェブアプリのURL |
CHATWORK_API_TOKEN | webhook編集画面のtoken |
[5] requestsライブラリが入ったzipフォルダを作成
※ lambda環境下ではpip installができないため、一度zipにしてからアップロードする必要がある
ローカル環境にて以下を実行
mkdir python
cd python
pip install -t ./ requests
cd ../
zip -r requests.zip python/
※ 最初に作成するフォルダはpythonという名称である必要がある
🖊参考
AWS Lambdaでレイヤー追加してもエラーが解決しないのはフォルダ名が問題だった
[6] zipフォルダをアップロードする
lambda ダッシュボード
-> レイヤー
-> レイヤーの作成をクリック
-> 適当な名称を付け、zipをアップロード(他の設定は特に必要ない
-> 作成したレイヤーのバージョンarnをメモ
[7] 作ったlambda関数内でrequestsを使えるようにする
関数作成画面下部レイヤーからレイヤーの追加をクリック
-> arnの指定をクリック
-> メモしたバージョンarnを入力し追加ボタンクリック
2 ApiGatewayの設定
[1] HTTP APIの構築
aws ApiGatewayを開く
-> apiの作成をクリック(過去に使ってないと出ないかも)
-> HTTP API の構築をクリック
[2] 統合を作成
統合のプルダウンからlambda
-> Lambda関数で先ほど作った関数を指定
-> 適当なapi名を付ける
-> 次へ
[3] ルートの設定(ステージはなにもしない)
メソッドをpostに変更
-> 次へ
-> ステージはそのままで次へ
[4] 作成したapi_gatewayのurlをwebhookの編集にて入力
とりあえず入力しておいた、スプレッドシートウェブアプリのURLを削除してapi_gatewayのurlを入力
以上で特定のメッセージルームでメッセージが飛び交うたびに
スプレッドシートに内容が転記されるようになっているはずです。
おわりに
最初から記事にするつもりはなかったため、ところどころ抜けがあるかもしれません。
抜けがあったら申し訳ないです。
また、lambdaで実装した署名検証をlambda authorizerとして別に作るのも面白そうなので、
気が向いたら作ってみるのもいいかなと思いました。
参考
チャットワークのwebhookの署名検証をPythonで実装してみた
aws lambda に外部ライブラリをインストールする方法
chatwork to Discord webhookを使ったLambda python
【GAS】チャットワークのメッセージを取り出す関数とメッセージを送る関数