pythonで書いたlambdaのreturnはjson.dumps()されている

# はじめに
もうタイトルがそのまんま結論なんですけど、
色々読んで試してやっと自分の中で解決したので記事にします。

対象読者は
+ 公式ディベロッパーズガイドを読んでもあまりピンと来なかった方
+ 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/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](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関数は
いろんな処理すっ飛ばして簡単にすると以下のような感じでした。

```python
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はこんな感じ
```python
Response
{
  "statusCode": 200,
  "body": "{\"result\": \"hogehoge\"}"
}

"""
ほんとは以下のように出力してほしい
Response
{
  "statusCode": 200,
  "body": "{"result": "hogehoge"}"
}
"""
```
めっちゃいらんバックスラッシュついとる...
そりゃkey読めませんわ...

[このExamples](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/python-handler.html#python-example)を見ながら書いていたので
bodyはjson形式にした値を入れなきゃなんだなあと勝手に思っていたのですが違っていました。

# 試してみた
公式のディベロッパーズガイドからなんとなくreturnそのものがjson.dumps()されているのではないか
ということを察したので、いくつか試してみることにしました。

### その１：json.dumps()したものをjson.dumps()するとどうなる？
察したことが正しいか試すためにまずjson.dumps()したものをjson.dumps()してみました
```python
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形式にするためにはダブルクオーテーションのまえにはバックスラッシュがつくので、そのせいですね。

### その２：returnを前もってjson.dumps()しておくとどうなる？
lambda関数のreturnに渡すものを前もってjson.dumps()してみます。

```python
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は以下の通りです
```python
Response
"{\"statusCode\": 200, \"body\": {\"result\": \"hogehoge\"}}"
```
responseがjson.dumps()したものをjson.dumps()した形になっていますね。

# 意図した出力を得るためには
ということで意図した出力を得るためにはdictをそのまま渡してあげればよかったです。
```python
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://qiita.com/momonoki1990/items/cd9a65498c2b16b0ed55)
+ 同じように悩んでる人いたけど回答の理由がわからなくてそこから暫し調べた
[https://teratail.com/questions/346091](https://teratail.com/questions/346091)
+ 公式の言葉の意味調べるのにいろいろ読みました
[https://dev.classmethod.jp/articles/lambda-idempotency/](https://dev.classmethod.jp/articles/lambda-idempotency/)
[https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/invocation-sync.html](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://docs.python.org/ja/3/library/json.html#json.dumps)
[https://note.nkmk.me/python-json-load-dump/](https://note.nkmk.me/python-json-load-dump/)