AWS samでローカルのテストは通ったけど、AWS上のAPIGateWay+Lambdaでは通らなかったときの解消法


まえがき

AWS APIGateWay+Lambdaを利用してサーバレスでシステムを組んでいる。
ローカルでsamを利用してテストが通ったので、AWS上で動かしたところうまく動かなかったことがあるので解決策を記述する。
なお、runtimeとしてgo1.xを利用した。

sam initでテストアプリを作成する

 sam init --runtime go1.x --name test-app

でsample applicationを作成する。
ここで生成されるテンプレートアプリケーションを変更し、Postされたjsonの内容を返却するアプリケーションを作成する。

package main

import (
    "encoding/json"
    "fmt"

    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
)

type Parameter struct {
    ID string `json:"id"`
}

func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    body := request.Body
    jsonBytes := []byte(body)
    param := new(Parameter)
    if err := json.Unmarshal(jsonBytes, param); err != nil {
        return events.APIGatewayProxyResponse{}, err

    }

    return events.APIGatewayProxyResponse{
        Body:       fmt.Sprintf("ID, %v", param.ID),
        StatusCode: 200,
    }, nil
}

func main() {
    lambda.Start(handler)
}

Postを受けたいのでtemplate.yaml のResources.HelloWorldFunction.Properties.Events.CatchAll.Properties

のPathとMethodを以下のようにする

---
Properties:
  Path: /test
  Method: POST
---

その後 make build を実行し、sam local start-api を実行すればlocalでテストができる


curl -X POST \
  http://localhost:3000/test \
  -d '{
    "ID": "test"
}'
ID, test

テストできたので、AWS上でLambda,APIGatewayを作成し、 zipで固めたバイナリをLambda上にデプロイしたところ動作しなかった。

json.Unmarshalしたところでエラーが出ているようだった。

対処法

APIGateWayを作成したときに統合リクエストの部分で、Lambda プロキシ統合の使用にチェックを入れなかったのが原因。

sam initで生成されるテンプレートの handlerの引数である (request events.APIGatewayProxyRequest) は以下のような構造体となっている
https://github.com/aws/aws-lambda-go/blob/master/events/apigw.go#L6

Lambdaプロキシ統合の使用を利用すると APIGatewayから構造体にあったリクエストが飛んでくるようになるのでこれでリクエストを受けることができるようになった。

これをマッピングテンプレートで行おうとするとかなり大変なので便利な機能だなと思った。