Lambda + API Gatewayの初歩の初歩の初歩(レスポンス)で転んだ話
昔からプラモデルは説明書を読まずに組み合わせて後から絶望していました。反省が活かせていない。恥ずかしいけどまたやりそうなので備忘的に残します。
このごろAWSを久しぶりに触っているのですが、今まではCloud Watchのイベントスケジュール等でLambdaを殴って満足しておりました。ところがここにきて外部からのリクエストを受け付ける必要がでてきたので、3年くらい前に触ったAPI Gatewayの記憶を頼りに適当にLambdaとAPI Gatewayを繋いだら怒られました。
> Invoke-RestMethod -Uri $url -Method Get -Headers $token
Invoke-RestMethod : {"message": "Internal server error"}
発生場所 行:1 文字:1
+ Invoke-RestMethod -Uri $url -Method Get -Headers $token
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod]、WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
API Gatewayのテスト画面でレスポンスを見てみると・・・
Sun Jun 09 05:54:05 UTC 2019 : Execution failed due to configuration error: Malformed Lambda proxy response
Malformed Lambda proxy response
おやおや、Lambdaからのレスポンスがおかしいって言われてますね。
exports.handler = async (event, context, callback) => {
// TODO implement
var responseBody = {
"res1": "this is good response!"
};
const response = {
statusCode: 200,
body: responseBody
};
callback response;
};
もしかしてstatusCodeの返し方が違うの・・・?
と思ったら、ちゃんとドキュメントがありました。最初から読めばよかったですね。
body フィールドは、もし JSON を返すのであれば、それ以上のレスポンスの問題を防ぐために文字列に変換されなければなりません。JSON.stringify を使用すると、Node.js 関数でこれを処理できます。他のランタイムでは異なる解決方法が必要ですが、概念は同じです。
bodyはStringで渡しましょう。
そりゃそうだ。失礼しました。
ドキュメントに倣ってコードを修正。
exports.handler = async (event, context, callback) => {
// TODO implement
var responseBody = {
"res1": "this is good response!"
};
var response = {
"statusCode": 200,
"headers": {
"header1": "header-is-here"
},
"body": JSON.stringify(responseBody),
"isBase64Encoded": false
};
callback(null, response);
};
> Invoke-RestMethod -Uri $url -Method Get -Headers $token
res1
----
this is good response!
ちゃんと動きました。めでたしめでたし。