【AWS AppSync】HTTPリクエストで配列データを受け取る際のResolverについて

AWS AppSyncのデータソースとしてHTTPリクエストを使ってAPIから配列データを受け取りたいが、どうマッピングすれば良いのか分からずしばらく詰まってしまった時の備忘録。

###SchemaとQuery
ECSで動いているAPIへ、userIdをキーにリクエスト投げて、Transactionオブジェクトの配列データを受け取るSchema。

```graphql:Schema
type ListTransactionsResponse {
	statusCode: Int!
	transactions: [Transaction]
}

type Query {
	listTransactions(userId: String!): ListTransactionsResponse
}

type Transaction {
	transactionId: String!
	transactionDate: String!
	transactionType: String!
}
```

```graphQl:Query
query listTransactions {
  listTransactions(userId: "123456"){
    statusCode
    transactions{
      transactionId
      transactionDate
      transactionType
    }
  }
}
```

###Resolver
アプリ側のレスポンスのbodyにレコードを格納しているので、アプリからのResponseの中身としてはcontext.result.bodyに欲しいデータが格納されている。

```json:response/context
  "context": {
    "arguments": {
      "userId": "123456"
    },
    "result": {
      "headers": {
        "Content-Length": "496",
        "Content-Type": "application/json",
        "Date": "Wed, 27 Feb 2019 04:59:03 GMT",
        "x-amz-apigw-id": "VvjbmG6RvHcFrpA=",
        "x-amzn-RequestId": "66efd625-3a4c-11e9-8292-c1ffb3d8ffa7",
        "X-Amzn-Trace-Id": "Root=1-5c761917-95fe6e504485a250d04c2da0"
      },
      "statusCode": 200,
      "body": "{\n    \"transactions\": [\n        {\n            \"transactionId\": 001,\n            \"transactionDate\": \"2019-02-26 10:50:44\",\n            \"transactionType\": \"入金\"\n        },{\n            \"transactionId\": 002,\n            \"transactionDate\": \"2019-02-26 12:10:12\",\n            \"transactionType\": \"送金\"\n        },{\n            \"transactionId\": 003,\n            \"transactionDate\": \"2019-02-26 12:12:34\",\n            \"transactionType\": \"送金\"\n        }]\n}"
    },
    "stash": {},
    "outErrors": []
  },
```

例えばDynamoDBをデータソースに指定している場合は、凡そ以下のシンプルなマッピングで問題なかったが、今回はこのままだとQueryへのレスポンスとして正しく受け取れないため、正しいマッピングをしてあげる必要がある。

```
$util.toJson($ctx.result)
```

```json:Queryへのレスポンスがこうなってしまう
{
  "data": {
    "listTransactions": {
      "statusCode": 200,
      "transactions": null
    }
  }
}
```
  
  

そこで、Transactionオブジェクト配列が格納されたbody部分をfor文で回しながら1レコードずつマッピングしてあげると、

```text:response_mapping_template
#set ($bodyObj = $util.parseJson($context.result.body))
{
	"statusCode": $context.result.statusCode,
	"transactions": [
          #foreach($transaction in $bodyObj.transactions)
              {
                  "transactionId" : "$transaction.transactionId",
                  "transactionDate" : "$transaction.transactionDate",
                  "transactionType" : "$transaction.transactionType"
              }
          #if($foreach.hasNext),#end
          #end
    ]
}
```

```json:
{
  "data": {
    "listTransactions": {
      "statusCode": 200,
      "transactions": [
        {
          "transactionId": "001",
          "transactionDate" : "2019-02-26 10:50:44",
          "transactionType" : "入金"
        },
        {
          "transactionId": "002",
          "transactionDate" : "2019-02-26 12:10:12",
          "transactionType" : "送金"
        },
        {
          "transactionId": "003",
          "transactionDate" : "2019-02-26 12:12:34",
          "transactionType" : "送金"
        }
      ]
    }
  }
}
```

上手くいった！

要はレスポンスの中身ちゃんと意識してマッピング考えないとだめですよね、っていうお粗末な話でした。