はじめに
もうタイトルがそのまんま結論なんですけど、
色々読んで試してやっと自分の中で解決したので記事にします。
対象読者は
- 公式ディベロッパーズガイドを読んでもあまりピンと来なかった方
- lambdaからの返り値に無駄にバックスラッシュついてて困ってる方
です。
結論
pythonで書いたlambdaのreturnはjson.dumps()されています。
なので一度json.dumps()したものを要素として渡すと
意図しないバックスラッシュがついてきます。
公式のディベロッパーズガイドの「値の返し(Returning a value)」のところ読むと書いてあるんですが、
最初は日本語版読んでも意味わかんなくて
英語で読んでやっとあれ?となって
いろいろ試してやっと「そういうことか!」となりました。
公式のディベロッパーズガイドはこちら
日本語版:https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/python-handler.html#python-handler-return
英語版:https://docs.aws.amazon.com/lambda/latest/dg/python-handler.html#python-handler-return
何で困った?
お試しでCloudFlont+S3+API Gateway+Lambda使ったアプリを作ってみていたところ
(他にもいっぱいトラブったので今度記事にしたい)
最終的にフロントエンドに返ってきた値がどうもうまく取得できてないぞとなったことがきっかけでした。
(fetch使ってPOSTした後にresponseのbodyをresponse.json()→data.keyで取得しようとしたところ、data.keyの値がundefinedになっていた)
その時書いてたLambda関数は
いろんな処理すっ飛ばして簡単にすると以下のような感じでした。
import json
def lambda_handler(event, context):
result = "hogehoge"
dict = {"result":result}
json_data = json.dumps(dict)
return {
'statusCode': 200,
'body':json_data
}
そんでもってTestしてみると返ってきたResponseはこんな感じ
Response
{
"statusCode": 200,
"body": "{\"result\": \"hogehoge\"}"
}
"""
ほんとは以下のように出力してほしい
Response
{
"statusCode": 200,
"body": "{"result": "hogehoge"}"
}
"""
めっちゃいらんバックスラッシュついとる...
そりゃkey読めませんわ...
このExamplesを見ながら書いていたので
bodyはjson形式にした値を入れなきゃなんだなあと勝手に思っていたのですが違っていました。
試してみた
公式のディベロッパーズガイドからなんとなくreturnそのものがjson.dumps()されているのではないか
ということを察したので、いくつか試してみることにしました。
その1:json.dumps()したものをjson.dumps()するとどうなる?
察したことが正しいか試すためにまずjson.dumps()したものをjson.dumps()してみました
dict = {"result":"hogehoge"}
json_dumps_1 = json.dumps(dict)
json_dumps_2 = json.dumps(json_dumps_1)
print(json_dumps_1) #print結果→ {"result": "hogehoge"}
print(json_dumps_2) #print結果→ "{\"result\": \"hogehoge\"}"
json_dumps_2の結果が先のresponseのbodyのvalueと同じような形になっています。
json形式にするためにはダブルクオーテーションのまえにはバックスラッシュがつくので、そのせいですね。
その2:returnを前もってjson.dumps()しておくとどうなる?
lambda関数のreturnに渡すものを前もってjson.dumps()してみます。
import json
def lambda_handler(event, context):
result = "hogehoge" # 仮にhogehogeとしとく
dict = {"result":result}
return_obj ={
'statusCode': 200,
'body':dict
}
return_obj_json = json.dumps(return_obj)
print(return_obj_json) # {"statusCode": 200, "body": {"result": "hogehoge"}}
return return_obj_json
このときのresponseは以下の通りです
Response
"{\"statusCode\": 200, \"body\": {\"result\": \"hogehoge\"}}"
responseがjson.dumps()したものをjson.dumps()した形になっていますね。
意図した出力を得るためには
ということで意図した出力を得るためにはdictをそのまま渡してあげればよかったです。
import json
def lambda_handler(event, context):
result = "hogehoge"
dict = {"result":result}
return {
'statusCode': 200,
'body':dict
}
この時のresponseは以下です
Response
{
"statusCode": 200,
"body": {
"result": "hogehoge"
}
}
うまくいきました!
おわりに
公式の日本語をちゃんと理解できなかったばっかりに
だいぶ悩んだのですが
JSONなんたるや(誤解してた)から復習できて
とてもいい機会になりました。
その他参考
- JSONなんたるやを復習できました
https://qiita.com/momonoki1990/items/cd9a65498c2b16b0ed55 - 同じように悩んでる人いたけど回答の理由がわからなくてそこから暫し調べた
https://teratail.com/questions/346091 - 公式の言葉の意味調べるのにいろいろ読みました
https://dev.classmethod.jp/articles/lambda-idempotency/
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/invocation-sync.html - json.dumps()の挙動もよくわかっていない気がしたから調べました
https://docs.python.org/ja/3/library/json.html#json.dumps
https://note.nkmk.me/python-json-load-dump/