[demo(単体テスト)] センサー情報処理: Lambdaの単体テストをしてみる→LambdaをCLIから呼び出すと「Invalid base64」でJSONペイロードにハマる。

AWS

Lambda を aws lambda invoke コマンドで直接テストしようとした際に、「Invalid base64」「Could not parse payload into json」 といったエラーにハマりました。


やりたかったこと

センサーデータを API Gateway 経由で受け取る Lambda を想定。
CLI からLambdaの単体テストしてみる。→「Invalid base64」エラー

{
  "body": "{\"sensor_id\": \"car-001\", \"timestamp\": \"2025-03-23T12:34:56Z\", \"temperature\": 24.5, \"speed\": 50.0}"
}
Code language: JSON / JSON with Comments (json)

しかしこの JSON ペイロードで Lambda を呼び出すと、さまざまなエラーが発生。。


最初のエラー:UTF-8のエンコーディングエラー

Could not parse request body into json: Invalid UTF-8 start byte 0x87

ファイルが Shift_JISやASCII で保存されているのが原因の様子。

UTF-8 に変換(macOS)

iconv -f US-ASCII -t UTF-8 test-payload.json > test-payload-utf8.jsonCode language: CSS (css)

次のエラー:「Invalid base64」

Invalid base64: "{"body":"{...}"}"Code language: JavaScript (javascript)

このエラーは、--cli-binary-format オプションを付けていないことで、CLIがJSONをBase64として解釈しようとしたことが原因でした。


解決手順まとめ

  1. JSONを1行で整形
  2. –cli-binary-format オプションを追加

この実行で無事、以下のような成功レスポンスが返ってくる

akira_mba@amba cfn-demo-api_lambda_waf % aws lambda invoke \
  --function-name ApiWafDemoFunction \
  --payload '{"body":"{\"sensor_id\": \"car-001\", \"timestamp\": \"2025-03-23T12:34:56Z\", \"temperature\": 24.5, \"speed\": 50.0}"}' \
  --cli-binary-format raw-in-base64-out \
  output.json

{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}
akira_mba@amba cfn-demo-api_lambda_waf % 

メモ

・API Gatewayからデータを送る場合は、文字列で送られる
 (サンプル)
 "body": "{\"sensor_id\": \"car-001\", \"temperature\": 24.5, \"speed\": 50.0}"
 →文字列としてエスケープされたJSON(JSON構造ではない)

・今回、API Gatewayからデータを受け取る想定でLambda関数を作成した
 (文字列で受け取ることを想定)

・Lambda関数ではデータの処理はPythonで処理できるdict型(JSONと構造が同じ形式)にする必要がある
 そのため、以下で定義した
 ### ingest_vehicle_sensor.py ### 
 def lambda_handler(event, context):
 body = event.get("body")
 payload = json.loads(body)  # JSON文字列 → dict : "文字列(文字列としてエスケープされたJSON)"をPythonの辞書にする 
 ...
 ######################

・なので、aws lambda invoke コマンドでテストする時は、JSON形式で渡さずに、文字列型で渡す必要がある。

Code language: PHP (php)


CloudWatch Logsでの確認

aws logs get-log-events コマンドで Lambda のログを取得し、正しくセンサーデータが記録されていることを確認

akira_mba@amba cfn-demo-api_lambda_waf % aws logs get-log-events \
  --log-group-name /aws/lambda/ApiWafDemoFunction \
  --log-stream-name '2025/03/29/[$LATEST]c5718097ca18438cb6429a8e4798b829'
<省略>
    "events": [
        {
            "timestamp": 1743252382479,
            "message": "INIT_START Runtime Version: python:3.9.v82\tRuntime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:d6dc717114b06da7d4b5a2df328222709ec4fad2853004fac301b8b63a65c084\n",
            "ingestionTime": 1743252387405
        },
        {
            "timestamp": 1743252382559,
            "message": "START RequestId: 4af0cf07-a5a1-4b81-af20-6f6c697058ef Version: $LATEST\n",
            "ingestionTime": 1743252387405
        },
        {
            "timestamp": 1743252382560,
            "message": "[INFO]\t2025-03-29T12:46:22.559Z\t4af0cf07-a5a1-4b81-af20-6f6c697058ef\tReceived sensor data: {\"sensor_id\": \"car-001\", \"timestamp\": \"2025-03-23T12:34:56Z\", \"temperature\": 24.5, \"speed\": 50.0, \"source_ip\": \"N/A\"}\n",
            "ingestionTime": 1743252387405
        },
        {
            "timestamp": 1743252382574,
            "message": "END RequestId: 4af0cf07-a5a1-4b81-af20-6f6c697058ef\n",
            "ingestionTime": 1743252387405
        },
<省略>
  

これで Lambda 関数が想定通りに動作していることが確認できました。

補足:
ログストリーム名の $LATEST[ ]の特殊文字含んでいる
Bash、Zshではダブルクォート「”」で囲むと$が環境変数で展開される
シングルクォート「’」で囲むと完全な文字列で扱われる

akira_mba@amba cfn-demo-api_lambda_waf % aws logs get-log-events \
  --log-group-name /aws/lambda/ApiWafDemoFunction \
  --log-stream-name "2025/03/29/[$LATEST]c5718097ca18438cb6429a8e4798b829"


An error occurred (ResourceNotFoundException) when calling the GetLogEvents operation: The specified log stream does not exist.
akira_mba@amba cfn-demo-api_lambda_waf % 


まとめ

問題対策
文字コードエラーUTF-8に変換する
JSON構文エラー1行のJSON形式で保存
Invalid base64--cli-binary-format raw-in-base64-out を明示