Amazon S3からファイルを取得してSlackに添付ファイルとして投稿するAWS Lambdaを作っていたが、AWS LambdaのPython環境にはrequestsモジュールが入っていなかったので苦戦した。
前提・環境
AWS Lambda Python環境
やりたかった事
- Amazon S3からファイルを取得する
- ファイルをSlackの
files.upload
APIで添付ファイルとして投稿する(content typeはmultipart/form-dataを使う)
できなかったこととその理由
Pythonでのファイルのアップロードは、
https://qiita.com/5zm/items/92cde9e043813e02eb68
や
https://www.it-swarm-ja.tech/ja/python/python%E3%81%A7%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%81%A8-multipart-formdata%E3%82%92%E9%80%81%E4%BF%A1%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%EF%BC%9F/1069592211/
にあるように、requestsを使うのが定番。
しかしAWS LambdaのPython環境にはrequestsモジュールが入っていなかった。
解決方法
- requestsの含まれるLambda Layerを使う
- requestsではなくurllib.requestを使う <- 採用
実装
urllib.requestを使うと言ってもmultipart form dataを作成する必要があるので以下のURLを参考にした。
https://necoyama3.hatenablog.com/entry/20150608/1434982490
この記事内に記載にあるencode_multipart_formdata
メソッドはデータ部とファイル部をmultipart form dataの形式に変換してくれる。
これを利用して以下のようにした。
## ポイント1: fileパラメータを除いたパラメータを定義する
data = {
'token': <your token>,
'channels': <your channels>,
'initial_comment': key + 'を投稿します:eyes:',
'filename': key,
'filetype': 'webp'
}
url = "https://slack.com/api/files.upload"
content = open('/tmp/' + key, 'rb').read()
## ポイント2: fileパラメータを定義する
file = {'file': {'filename': key, 'content': content}}
## ポイント3: dataとfileをひとつのmultipart form dataに変換する
content_type, body = encode_multipart_formdata(data, file)
header = {'Content-Type': content_type}
request = urllib.request.Request(url, body, header)
response = urllib.request.urlopen(request)
ポイントになるのは
-
data
変数でSlack files.upload APIのfileパラメータを除いたパラメータを定義する -
file
変数でSlack files.upload APIのfileパラメータを定義する -
encode_multipart_formdata
メソッドでmultipart form dataに変換する
の3点。
これでrequestsを使わずにAWS LambdaでSlackにファイルを投稿できるようになった。
最後に
Lambda Layerを作るのとどちらが楽なんだろうか…?