Lambda+API GatewayのレスポンスをJSONとしてパース出来ない
はじめに
「内閣府の祝日CSVをLambda上でJSON形式に加工して、API Gateway経由で使えるようにする」というプログラムを考えたのですが、API GatewayのレスポンスがJSONとして正しくパース出来ないことが分かりました。
Lambda上で動いているRubyプログラムは単体のスクリプトとして問題なく動作することを既に確認していましたが、原因が分かるまで少し時間がかかったので、その記録をまとめてみました。
使用した環境
- Lambda(Ruby)
- API Gateway
正しく動作しなかったコード
-
JSON.pretty_generate
やJSON.generate
、JSON.dump
などでシリアライズした結果を返すと、API Gatewayを通して取得したレスポンスの前後に不要なダブルクォート(")が付いてしまい、JSONとしてパース出来ませんでした。
- その後にさらに調べてみると、API Gatewayを通さずにLambda単体の状態でもレスポンスの前後に不要なダブルクォートが付いていたため、この現象がAPI Gatewayによるものではないと分かりました。
lambda_function.rb
require 'json'
require 'open-uri'
def lambda_handler(event:, context:)
csv = OpenURI.open_uri('https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv') {|io|
io.read
}
csv = csv.force_encoding("sjis")
array = []
csv.split(/\r\n|\r|\n/).each_with_index {|row, i|
next if (i==0) # ヘッダ行は読み飛ばす
buffs = row.split(",")
hash = {"date": buffs[0], "name": buffs[1]}
array.push(hash)
}
return JSON.pretty_generate(array) # この行をJSON.generate()やJSON.dump()に変えても結果は変わらず...
end
出力結果の例
"[\n {\n \"date\": \"1955/1/1\",\n \"name\": \"元日\"\n },...,\n {\n \"date\": \"2020/11/23\",\n \"name\": \"勤労感謝の日\"\n }\n]"
正しく動作したコード
-
こちらのページに書かれているように、シリアライズせずにオブジェクトをそのまま返す形にコードを直したところ、正しいJSONをレスポンスとして受け取れるようになりました。
- どうやら、 「Lambdaの関数の戻り値として文字列のJSONを指定すると、JSONとして二重にシリアライズされてしまう」 ことが今回の問題の原因のようです。
lambda_function.rb
require 'json'
require 'open-uri'
def lambda_handler(event:, context:)
csv = OpenURI.open_uri('https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv') {|io|
io.read
}
csv = csv.force_encoding("sjis")
array = []
csv.split(/\r\n|\r|\n/).each_with_index {|row, i|
next if (i==0) # ヘッダ行は読み飛ばす
buffs = row.split(",")
hash = {"date": buffs[0], "name": buffs[1]}
array.push(hash)
}
return array # ArrayやHashなどのオブジェクトをそのまま返せばOK!
end
出力結果の例
[{"date":"1955/1/1","name":"元日"},...,{"date":"2020/11/23","name":"勤労感謝の日"}]
まとめ
- ある程度調べたところでLambdaの仕様による現象だと分かっていたものの、中々解決策が見つからずに苦労しました。
- 上記の仕様について、AWS公式ページのどこかに記載されているのかもしれませんが、大事な事なのでもう少し分かりやすく書いて欲しかったです。
- もしかしたら私が気付かなかっただけで、どこかに明記されていたのかもしれません。
- あるいは私がLambda初心者で知らなかっただけで、暗黙知だったのかもしれませんが...
-
JSON.pretty_generate
やJSON.generate
、JSON.dump
などでシリアライズした結果を返すと、API Gatewayを通して取得したレスポンスの前後に不要なダブルクォート(")が付いてしまい、JSONとしてパース出来ませんでした。- その後にさらに調べてみると、API Gatewayを通さずにLambda単体の状態でもレスポンスの前後に不要なダブルクォートが付いていたため、この現象がAPI Gatewayによるものではないと分かりました。
lambda_function.rb
require 'json'
require 'open-uri'
def lambda_handler(event:, context:)
csv = OpenURI.open_uri('https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv') {|io|
io.read
}
csv = csv.force_encoding("sjis")
array = []
csv.split(/\r\n|\r|\n/).each_with_index {|row, i|
next if (i==0) # ヘッダ行は読み飛ばす
buffs = row.split(",")
hash = {"date": buffs[0], "name": buffs[1]}
array.push(hash)
}
return JSON.pretty_generate(array) # この行をJSON.generate()やJSON.dump()に変えても結果は変わらず...
end
出力結果の例
"[\n {\n \"date\": \"1955/1/1\",\n \"name\": \"元日\"\n },...,\n {\n \"date\": \"2020/11/23\",\n \"name\": \"勤労感謝の日\"\n }\n]"
正しく動作したコード
-
こちらのページに書かれているように、シリアライズせずにオブジェクトをそのまま返す形にコードを直したところ、正しいJSONをレスポンスとして受け取れるようになりました。
- どうやら、 「Lambdaの関数の戻り値として文字列のJSONを指定すると、JSONとして二重にシリアライズされてしまう」 ことが今回の問題の原因のようです。
lambda_function.rb
require 'json'
require 'open-uri'
def lambda_handler(event:, context:)
csv = OpenURI.open_uri('https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv') {|io|
io.read
}
csv = csv.force_encoding("sjis")
array = []
csv.split(/\r\n|\r|\n/).each_with_index {|row, i|
next if (i==0) # ヘッダ行は読み飛ばす
buffs = row.split(",")
hash = {"date": buffs[0], "name": buffs[1]}
array.push(hash)
}
return array # ArrayやHashなどのオブジェクトをそのまま返せばOK!
end
出力結果の例
[{"date":"1955/1/1","name":"元日"},...,{"date":"2020/11/23","name":"勤労感謝の日"}]
まとめ
- ある程度調べたところでLambdaの仕様による現象だと分かっていたものの、中々解決策が見つからずに苦労しました。
- 上記の仕様について、AWS公式ページのどこかに記載されているのかもしれませんが、大事な事なのでもう少し分かりやすく書いて欲しかったです。
- もしかしたら私が気付かなかっただけで、どこかに明記されていたのかもしれません。
- あるいは私がLambda初心者で知らなかっただけで、暗黙知だったのかもしれませんが...
lambda_function.rb
require 'json'
require 'open-uri'
def lambda_handler(event:, context:)
csv = OpenURI.open_uri('https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv') {|io|
io.read
}
csv = csv.force_encoding("sjis")
array = []
csv.split(/\r\n|\r|\n/).each_with_index {|row, i|
next if (i==0) # ヘッダ行は読み飛ばす
buffs = row.split(",")
hash = {"date": buffs[0], "name": buffs[1]}
array.push(hash)
}
return array # ArrayやHashなどのオブジェクトをそのまま返せばOK!
end
出力結果の例
[{"date":"1955/1/1","name":"元日"},...,{"date":"2020/11/23","name":"勤労感謝の日"}]
- ある程度調べたところでLambdaの仕様による現象だと分かっていたものの、中々解決策が見つからずに苦労しました。
- 上記の仕様について、AWS公式ページのどこかに記載されているのかもしれませんが、大事な事なのでもう少し分かりやすく書いて欲しかったです。
- もしかしたら私が気付かなかっただけで、どこかに明記されていたのかもしれません。
- あるいは私がLambda初心者で知らなかっただけで、暗黙知だったのかもしれませんが...
Author And Source
この問題について(Lambda+API GatewayのレスポンスをJSONとしてパース出来ない), 我々は、より多くの情報をここで見つけました https://qiita.com/nkojima/items/68082034da708c856067著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .