この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
Pythonでrequests
ライブラリを使いたいとき、Boto3のbotocore.vendored.requests
を使っている方もいると思います。
requestsライブラリをデプロイパッケージに含まなくて良いのは楽ちんなのです。 特にLambda関数でrequestsしか使っていない場合とかですね。
しかし、下記にあるように、botocore.vendored.requests
が無くなりました。
そこで本記事では、requests
ライブラリを追加で導入することなく置き換える方法をご紹介します。
Lambdaのbotocore.vendored.requests
を置き換える方法
2つの方法があります。
requests
ライブラリを導入する- メリット
- コードの変更は
import
部分だけで済む
- コードの変更は
- デメリット
- デプロイフローの変更が必要
- デプロイパッケージに
requests
を含むようにする - ただし、他のライブラリを使用している場合、このデメリットは無い
- デプロイパッケージに
- デプロイフローの変更が必要
- メリット
- 標準の
urllib.requests
を使用する- メリット
- デプロイフローの変更が不要
- デメリット
- コードの変更量が多い
- メリット
本記事では後者を扱います。
ただし、オススメはrequestsライブラリの導入
コードの変更はimport
の変更だけで済みます。
また、Lambdaのベストプラクティス的にも、依存関係(ライブラリ等)はデプロイパッケージに含むことがオススメされています。
AWS Lambda 実行環境には、Node.js および Python ランタイムの AWS SDK などのライブラリがいくつか含まれています。最新の機能やセキュリティ更新プログラムを有効にするために、Lambda ではこれらのライブラリを定期的に更新します。この更新に伴って、Lambda 関数の動作が微妙に変わる場合があります。関数で使用する依存関係を完全に制御するには、すべての依存関係をデプロイパッケージでパッケージングすることをお勧めします。
今回のBoto3の変更についても、デプロイパッケージにBoto3(特定バージョン)を含んでおけば、すぐにLambdaで使えなくなることはありません。
標準のurllib.requests
を使用する
公式ドキュメントは下記です。
使い方の例
下記のように使用できます。
http_client.py
import json
import urllib.request
def post(url: str, data: dict, headers:dict ={}):
req = urllib.request.Request(url,
data=json.dumps(data).encode('utf-8'),
headers=headers,
method='POST')
return urllib.request.urlopen(req)
def put(url: str, data: dict, headers:dict ={}):
req = urllib.request.Request(url,
data=json.dumps(data).encode('utf-8'),
headers=headers,
method='PUT')
return urllib.request.urlopen(req)
def delete(url: str, data: dict, headers:dict ={}):
req = urllib.request.Request(url,
data=json.dumps(data).encode('utf-8'),
headers=headers,
method='DELETE')
return urllib.request.urlopen(req)
def get(url: str):
req = urllib.request.Request(url, method='GET')
return urllib.request.urlopen(req)
sample.py
import urllib
import http_client as requests
def sample_get():
try:
res = requests.get('https://checkip.amazonaws.com/')
except urllib.error.HTTPError as e:
print(e.code)
print(e.reason)
else:
print(res.status)
print(res.read().decode('utf-8'))
def sample_post():
headers = {
'Content-Type': 'application/json; charset=utf-8'
}
payload = {
'hoge': 'fuga'
}
try:
res = requests.post('https://xxxx.com', payload, headers)
except urllib.error.HTTPError as e:
print(e.code)
print(e.reason)
else:
print(res.status)
print(res.read().decode('utf-8'))
if __name__ == "__main__":
sample_get()
sample_post()
import http_client as requests
として利用すれば、呼び出し時のI/Fをそのまま利用できるため、少しは楽になります。
(夏目さんに教えていただきました!)
例外処理を書く必要があるため、冗長にならざるを得ません。
このあたりもhttp_client.py
にまとめて、requests
ライブラリと同じように使えるようにするとさらに便利かと思います。
(だけどそこまでするなら、素直にrequests
ライブラリを使ったほうが良いかもしれない……)
上記を実行してみた結果
次のようになります。(IPアドレスは適当に変更しています)
$ python sample.py
200
111.111.111.111
403
Forbidden
さいごに
HTTP通信しかしないような単純なLambdaであれば、簡単に利用できそうですね。 (Slack通知するだけのLambdaとか)
参考
- urllib.request --- URL を開くための拡張可能なライブラリ — Python 3.7.5 ドキュメント
- urllib.error --- urllib.request が投げる例外 — Python 3.7.5 ドキュメント
- Python Boto3のAttributeError: module ‘botocore.vendored.requests’ has no attribute エラーを解決するには? | DevelopersIO
- 「botocore.vendored」のrequestsとurllib3は、そのうち使えなくなります。 Lambda等で使用中の場合は忘れないうちに対応しましょう! | DevelopersIO
- Python の HTTP クライアントは urllib.request で十分 - Qiita
- AWS Lambda 関数を使用する際のベストプラクティス - AWS Lambda