자습서: DynamoDB 배치 해석기 - AWS AppSync

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

자습서: DynamoDB 배치 해석기

참고

이제 우리는 주로 APPSYNC_JS 런타임과 해당 문서를 지원합니다. 여기에서 APPSYNC_JS 런타임과 해당 안내서를 사용해 보세요.

AWS AppSync에서는 단일 리전에 있는 하나 이상의 테이블에서 AppSync DynamoDB 배치 작업 사용을 지원합니다. 지원되는 작업은 BatchGetItem, BatchPutItemBatchDeleteItem입니다. AWS AppSync의 이러한 기능을 사용하면 다음과 같은 작업을 수행할 수 있습니다.

  • 단일 쿼리에서 키 목록을 전달하고 테이블의 결과 반환

  • 단일 쿼리의 하나 이상의 테이블에서 레코드 읽기

  • 하나 이상의 테이블에 대량으로 레코드 쓰기

  • 관계가 있을 수 있는 여러 테이블에서 조건부로 레코드 쓰기 또는 삭제

AWS AppSync에서 DynamoDB와 함께 배치 작업을 사용하는 것은 백엔드 작업 및 테이블 구조에 대한 사고와 지식이 조금 더 필요한 고급 기술입니다. 또한 AWS AppSync의 배치 작업에는 배치가 아닌 작업과 크게 차이나는 점이 2개 있습니다.

  • 데이터 원본 역할에 해석기가 액세스할 모든 테이블에 대한 권한이 있어야 합니다.

  • 해석기에 대한 테이블 사양이 매핑 템플릿의 일부입니다.

권한

다른 해석기와 마찬가지로 AWS AppSync에서 데이터 소스를 생성하고 역할을 생성하거나 기존 역할을 사용해야 합니다. 배치 작업에는 DynamoDB 테이블에 대한 여러 권한이 필요하기 때문에 읽기 또는 쓰기 작업에 대해 구성된 역할 권한을 부여해야 합니다.

{ "Version": "2012-10-17", "Statement": [ { "Action": [ "dynamodb:BatchGetItem", "dynamodb:BatchWriteItem" ], "Effect": "Allow", "Resource": [ "arn:aws:dynamodb:region:account:table/TABLENAME", "arn:aws:dynamodb:region:account:table/TABLENAME/*" ] } ] }

참고: 역할은 AWS AppSync의 데이터 소스에 연결되어 있고 필드의 해석기는 데이터 소스에 대해 호출됩니다. DynamoDB에 대해 가져오도록 구성된 데이터 소스에는 구성을 간단하기 유지하기 위해 지정된 테이블이 하나뿐입니다. 따라서 단일 해석기에서 여러 테이블에 대해 배치 작업을 수행하는 경우(고급 작업임) 데이터 원본 액세스에 대한 역할을 해석기가 상호 작용하는 모든 테이블에 부여해야 합니다. IAM 정책의 리소스 필드에서 부여할 수 있습니다. 배치 호출을 수행하려는 테이블의 구성은 해석기 템플릿에서 수행되는데, 이 내용은 아래에서 설명합니다.

데이터 원본

간단하게 설명하기 위해 이 자습서에서 사용되는 모든 해석기에 대해 동일한 데이터 원본을 사용합니다. 데이터 소스 탭에서 새 DynamoDB 데이터 소스를 생성하고 BatchTutorial이라고 이름을 지정합니다. 테이블 이름은 배치 작업을 위한 요청 매핑 템플릿의 일부로 지정되므로 어떤 것이든 지정할 수 있습니다. 테이블의 이름을 empty라고 지정하겠습니다.

이 자습서의 경우 다음 인라인 정책이 적용된 역할이 모두 작동합니다.

{ "Version": "2012-10-17", "Statement": [ { "Action": [ "dynamodb:BatchGetItem", "dynamodb:BatchWriteItem" ], "Effect": "Allow", "Resource": [ "arn:aws:dynamodb:region:account:table/Posts", "arn:aws:dynamodb:region:account:table/Posts/*", "arn:aws:dynamodb:region:account:table/locationReadings", "arn:aws:dynamodb:region:account:table/locationReadings/*", "arn:aws:dynamodb:region:account:table/temperatureReadings", "arn:aws:dynamodb:region:account:table/temperatureReadings/*" ] } ] }

단일 테이블 배치

이 예에서는 배치 작업을 통해 항목을 추가 및 제거하려는 Posts라는 단일 테이블이 있다고 가정합니다. 다음 스키마를 사용하는데, 쿼리를 위해 ID 목록을 전달합니다.

type Post { id: ID! title: String } input PostInput { id: ID! title: String } type Query { batchGet(ids: [ID]): [Post] } type Mutation { batchAdd(posts: [PostInput]): [Post] batchDelete(ids: [ID]): [Post] } schema { query: Query mutation: Mutation }

다음 요청 매핑 템플릿을 사용하여 batchAdd() 필드에 해석기를 첨부합니다. 이렇게 하면 GraphQL input PostInput 형식의 각 항목을 자동으로 받아 BatchPutItem 작업에 필요한 맵을 빌드합니다.

#set($postsdata = []) #foreach($item in ${ctx.args.posts}) $util.qr($postsdata.add($util.dynamodb.toMapValues($item))) #end { "version" : "2018-05-29", "operation" : "BatchPutItem", "tables" : { "Posts": $utils.toJson($postsdata) } }

이 경우 응답 매핑 템플릿은 간단한 패스스루인데, 테이블 이름이 다음과 같이 컨텍스트 객체에 ..data.Posts로 추가됩니다.

$util.toJson($ctx.result.data.Posts)

이제 AWS AppSync 콘솔의 쿼리 페이지로 이동하여 다음 batchAdd 뮤테이션을 실행합니다.

mutation add { batchAdd(posts:[{ id: 1 title: "Running in the Park"},{ id: 2 title: "Playing fetch" }]){ id title } }

결과가 화면에 출력되어야 하며 DynamoDB 콘솔을 통해 두 값이 Posts 테이블에 기록되었는지 독립적으로 확인할 수 있습니다.

다음으로, 다음 요청 매핑 템플릿을 사용하여 batchGet() 필드에 해석기를 첨부합니다. 이렇게 하면 GraphQL ids:[] 형식의 각 항목을 자동으로 받아 BatchGetItem 작업에 필요한 맵을 빌드합니다.

#set($ids = []) #foreach($id in ${ctx.args.ids}) #set($map = {}) $util.qr($map.put("id", $util.dynamodb.toString($id))) $util.qr($ids.add($map)) #end { "version" : "2018-05-29", "operation" : "BatchGetItem", "tables" : { "Posts": { "keys": $util.toJson($ids), "consistentRead": true, "projection" : { "expression" : "#id, title", "expressionNames" : { "#id" : "id"} } } } }

이 경우 응답 매핑 템플릿은 다시 간단한 패스스루인데, 테이블 이름이 다시 컨텍스트 객체에 ..data.Posts로 추가됩니다.

$util.toJson($ctx.result.data.Posts)

이제 AWS AppSync 콘솔의 쿼리 페이지로 돌아가 다음 batchGet 쿼리를 실행합니다.

query get { batchGet(ids:[1,2,3]){ id title } }

앞서 추가한 두 id 값에 대한 결과를 반환해야 합니다. null 값은 값이 id3에 대해 반환되었습니다. 이는 Posts 테이블에 해당 값을 가진 레코드가 아직 없기 때문입니다. 또한, AWS AppSync에서는 쿼리에 키가 전달된 순서대로 결과를 반환하는데, 이는 AWS AppSync에서 사용자를 대신하여 수행하는 추가 기능입니다. batchGet(ids:[1,3,2)로 전환하면 순서가 바뀝니다. 또한 어떤 idnull 값을 반환하는지 알게 됩니다.

마지막으로, 다음 요청 매핑 템플릿을 사용하여 batchDelete() 필드에 해석기를 첨부합니다. 이렇게 하면 GraphQL ids:[] 형식의 각 항목을 자동으로 받아 BatchGetItem 작업에 필요한 맵을 빌드합니다.

#set($ids = []) #foreach($id in ${ctx.args.ids}) #set($map = {}) $util.qr($map.put("id", $util.dynamodb.toString($id))) $util.qr($ids.add($map)) #end { "version" : "2018-05-29", "operation" : "BatchDeleteItem", "tables" : { "Posts": $util.toJson($ids) } }

이 경우 응답 매핑 템플릿은 다시 간단한 패스스루인데, 테이블 이름이 다시 컨텍스트 객체에 ..data.Posts로 추가됩니다.

$util.toJson($ctx.result.data.Posts)

이제 AWS AppSync 콘솔의 쿼리 페이지로 돌아가 다음 batchDelete 뮤테이션을 실행합니다.

mutation delete { batchDelete(ids:[1,2]){ id } }

이제 id 12인 레코드가 삭제되어야 합니다. 앞에서 batchGet() 쿼리를 다시 실행하면 null을 반환해야 합니다.

다중 테이블 배치

또한 AWS AppSync에서는 여러 테이블 간에 배치 작업을 수행할 수 있습니다. 더 복잡한 애플리케이션을 빌드해 보겠습니다. 센서가 애완동물의 위치와 신체 온도를 보고하는 애완동물 건강 앱을 빌드한다고 가정해 보겠습니다. 센서는 배터리로 구동되며 몇 분마다 네트워크에 연결을 시도합니다. 센서가 연결을 설정하면 판독값을 AWS AppSync API로 전송합니다. 그런 다음 트리거가 데이터를 분석해 애완동물 주인에게 대시보드가 제공됩니다. 센서와 백엔드 데이터 스토어 간의 상호 작용에 대해 중점적으로 설명해 보겠습니다.

전제 조건으로 먼저 두 개의 DynamoDB 테이블을 만들어 보겠습니다. locationReadings는 센서 위치 판독값을 저장하고 temperatureReadings는 센서 온도 판독값을 저장할 것입니다. 두 테이블은 동일한 기본 키 구조를 공유하는데, sensorId (String)는 파티션 키이고, timestamp (String)는 정렬 키입니다.

다음 GraphQL 스키마를 사용해 보겠습니다.

type Mutation { # Register a batch of readings recordReadings(tempReadings: [TemperatureReadingInput], locReadings: [LocationReadingInput]): RecordResult # Delete a batch of readings deleteReadings(tempReadings: [TemperatureReadingInput], locReadings: [LocationReadingInput]): RecordResult } type Query { # Retrieve all possible readings recorded by a sensor at a specific time getReadings(sensorId: ID!, timestamp: String!): [SensorReading] } type RecordResult { temperatureReadings: [TemperatureReading] locationReadings: [LocationReading] } interface SensorReading { sensorId: ID! timestamp: String! } # Sensor reading representing the sensor temperature (in Fahrenheit) type TemperatureReading implements SensorReading { sensorId: ID! timestamp: String! value: Float } # Sensor reading representing the sensor location (lat,long) type LocationReading implements SensorReading { sensorId: ID! timestamp: String! lat: Float long: Float } input TemperatureReadingInput { sensorId: ID! timestamp: String value: Float } input LocationReadingInput { sensorId: ID! timestamp: String lat: Float long: Float }

BatchPutItem - 센서 판독값 기록

센서는 인터넷에 연결되면 판독값을 전송할 수 있어야 합니다. GraphQL 필드 Mutation.recordReadings가 센서가 판독값을 전송하는 데 사용할 API입니다. API를 실행하기 위해 해석기를 연결해 보겠습니다.

Mutation.recordReadings 필드 옆의 첨부를 선택합니다. 다음 화면에서 자습서 시작 부분에서 생성한 것과 같은 BatchTutorial 데이터 원본을 선택합니다.

다음 요청 매핑 템플릿을 추가해 보겠습니다.

요청 매핑 템플릿

## Convert tempReadings arguments to DynamoDB objects #set($tempReadings = []) #foreach($reading in ${ctx.args.tempReadings}) $util.qr($tempReadings.add($util.dynamodb.toMapValues($reading))) #end ## Convert locReadings arguments to DynamoDB objects #set($locReadings = []) #foreach($reading in ${ctx.args.locReadings}) $util.qr($locReadings.add($util.dynamodb.toMapValues($reading))) #end { "version" : "2018-05-29", "operation" : "BatchPutItem", "tables" : { "locationReadings": $utils.toJson($locReadings), "temperatureReadings": $utils.toJson($tempReadings) } }

보시다시피 BatchPutItem 작업을 통해 여러 테이블을 지정할 수 있습니다.

다음 응답 매핑 템플릿을 사용해 보겠습니다.

응답 매핑 템플릿

## If there was an error with the invocation ## there might have been partial results #if($ctx.error) ## Append a GraphQL error for that field in the GraphQL response $utils.appendError($ctx.error.message, $ctx.error.message) #end ## Also returns data for the field in the GraphQL response $utils.toJson($ctx.result.data)

배치 작업을 사용하면 호출 시 오류 및 결과가 둘 다 반환될 수 있습니다. 이러한 경우 몇 가지 오류 처리를 작업을 자유롭게 수행할 수 있습니다.

참고: $utils.appendError() 사용은 $util.error()와 유사하지만 매핑 템플릿 평가를 중단하지 않는다는 큰 차이점이 있습니다. 대신 필드에 오류가 있다는 신호를 보내지만 템플릿이 계속해서 평가되도록 하고 이어서 호출자에게 데이터를 반환합니다. 애플리케이션이 일부 결과를 반환해야 하는 경우에는 $utils.appendError()를 사용하는 것이 좋습니다.

해석기를 저장하고 AppSync AWS 콘솔의 쿼리 페이지로 이동합니다. 센서 판독값을 몇 개 전송해 보겠습니다!

다음 변형을 실행합니다.

mutation sendReadings { recordReadings( tempReadings: [ {sensorId: 1, value: 85.5, timestamp: "2018-02-01T17:21:05.000+08:00"}, {sensorId: 1, value: 85.7, timestamp: "2018-02-01T17:21:06.000+08:00"}, {sensorId: 1, value: 85.8, timestamp: "2018-02-01T17:21:07.000+08:00"}, {sensorId: 1, value: 84.2, timestamp: "2018-02-01T17:21:08.000+08:00"}, {sensorId: 1, value: 81.5, timestamp: "2018-02-01T17:21:09.000+08:00"} ] locReadings: [ {sensorId: 1, lat: 47.615063, long: -122.333551, timestamp: "2018-02-01T17:21:05.000+08:00"}, {sensorId: 1, lat: 47.615163, long: -122.333552, timestamp: "2018-02-01T17:21:06.000+08:00"} {sensorId: 1, lat: 47.615263, long: -122.333553, timestamp: "2018-02-01T17:21:07.000+08:00"} {sensorId: 1, lat: 47.615363, long: -122.333554, timestamp: "2018-02-01T17:21:08.000+08:00"} {sensorId: 1, lat: 47.615463, long: -122.333555, timestamp: "2018-02-01T17:21:09.000+08:00"} ]) { locationReadings { sensorId timestamp lat long } temperatureReadings { sensorId timestamp value } } }

하나의 변형으로 센서 판독값 10개를 전송했고, 판독값은 테이블 2개로 분할되어 있었습니다. DynamoDB 콘솔을 사용하여 데이터가 locationReadingstemperatureReadings 테이블 모두에 표시되는지 확인합니다.

BatchDeleteItem - 센서 판독값 삭제

마찬가지로 센서 판독값의 배치를 삭제해야 합니다. 이를 위해 Mutation.deleteReadings GraphQL 필드를 사용해 보겠습니다. Mutation.recordReadings 필드 옆의 첨부를 선택합니다. 다음 화면에서 자습서 시작 부분에서 생성한 것과 같은 BatchTutorial 데이터 원본을 선택합니다.

다음 요청 매핑 템플릿을 사용해 보겠습니다.

요청 매핑 템플릿

## Convert tempReadings arguments to DynamoDB primary keys #set($tempReadings = []) #foreach($reading in ${ctx.args.tempReadings}) #set($pkey = {}) $util.qr($pkey.put("sensorId", $reading.sensorId)) $util.qr($pkey.put("timestamp", $reading.timestamp)) $util.qr($tempReadings.add($util.dynamodb.toMapValues($pkey))) #end ## Convert locReadings arguments to DynamoDB primary keys #set($locReadings = []) #foreach($reading in ${ctx.args.locReadings}) #set($pkey = {}) $util.qr($pkey.put("sensorId", $reading.sensorId)) $util.qr($pkey.put("timestamp", $reading.timestamp)) $util.qr($locReadings.add($util.dynamodb.toMapValues($pkey))) #end { "version" : "2018-05-29", "operation" : "BatchDeleteItem", "tables" : { "locationReadings": $utils.toJson($locReadings), "temperatureReadings": $utils.toJson($tempReadings) } }

이 응답 매핑 템플릿은 Mutation.recordReadings에 사용한 것과 동일합니다.

응답 매핑 템플릿

## If there was an error with the invocation ## there might have been partial results #if($ctx.error) ## Append a GraphQL error for that field in the GraphQL response $utils.appendError($ctx.error.message, $ctx.error.message) #end ## Also return data for the field in the GraphQL response $utils.toJson($ctx.result.data)

해석기를 저장하고 AppSync AWS 콘솔의 쿼리 페이지로 이동합니다. 이제 센서 판독값 두 개를 삭제해 보겠습니다!

다음 변형을 실행합니다.

mutation deleteReadings { # Let's delete the first two readings we recorded deleteReadings( tempReadings: [{sensorId: 1, timestamp: "2018-02-01T17:21:05.000+08:00"}] locReadings: [{sensorId: 1, timestamp: "2018-02-01T17:21:05.000+08:00"}]) { locationReadings { sensorId timestamp lat long } temperatureReadings { sensorId timestamp value } } }

DynamoDB 콘솔을 사용하여 판독값 2개가 locationReadingstemperatureReadings 테이블에서 삭제되었는지 확인합니다.

BatchGetItem - 판독값 검색

애완동물 건강 앱의 또 다른 일반 작업은 특정 시점에 센서의 판독값을 검색하는 것입니다. 스키마의 Query.getReadings GraphQL 필드에 해석기를 연결해 보겠습니다. 연결을 선택하고 다음 화면에서 자습서 시작 부분에서 생성한 것과 같은 BatchTutorial 데이터 원본을 선택합니다.

다음 요청 매핑 템플릿을 추가해 보겠습니다.

요청 매핑 템플릿

## Build a single DynamoDB primary key, ## as both locationReadings and tempReadings tables ## share the same primary key structure #set($pkey = {}) $util.qr($pkey.put("sensorId", $ctx.args.sensorId)) $util.qr($pkey.put("timestamp", $ctx.args.timestamp)) { "version" : "2018-05-29", "operation" : "BatchGetItem", "tables" : { "locationReadings": { "keys": [$util.dynamodb.toMapValuesJson($pkey)], "consistentRead": true }, "temperatureReadings": { "keys": [$util.dynamodb.toMapValuesJson($pkey)], "consistentRead": true } } }

이제 BatchGetItem 작업을 사용합니다.

SensorReading 목록을 반환하도록 선택했으므로 응답 매핑 템플릿이 약간 다릅니다. 호출 결과를 원하는 모양으로 매핑해 보겠습니다.

응답 매핑 템플릿

## Merge locationReadings and temperatureReadings ## into a single list ## __typename needed as schema uses an interface #set($sensorReadings = []) #foreach($locReading in $ctx.result.data.locationReadings) $util.qr($locReading.put("__typename", "LocationReading")) $util.qr($sensorReadings.add($locReading)) #end #foreach($tempReading in $ctx.result.data.temperatureReadings) $util.qr($tempReading.put("__typename", "TemperatureReading")) $util.qr($sensorReadings.add($tempReading)) #end $util.toJson($sensorReadings)

해석기를 저장하고 AppSync AWS 콘솔의 쿼리 페이지로 이동합니다. 이제, 센서 판독값을 검색해 보겠습니다!

다음 쿼리를 실행합니다.

query getReadingsForSensorAndTime { # Let's retrieve the very first two readings getReadings(sensorId: 1, timestamp: "2018-02-01T17:21:06.000+08:00") { sensorId timestamp ...on TemperatureReading { value } ...on LocationReading { lat long } } }

AWS AppSync을 사용하여 DynamoDB 배치 작업을 사용하는 방법을 보여드렸습니다.

오류 처리

AWS AppSync에서 데이터 소스 작업은 때때로 일부 결과를 반환할 수 있습니다. 일부 결과는 작업의 출력이 일부 데이터와 오류로 구성된 경우를 나타내는 데 사용되는 용어입니다. 오류는 본질적으로 애플리케이션별로 처리되므로 AWS AppSync에서는 응답 매핑 템플릿에서 오류를 처리할 수 있는 기회를 제공합니다. 해석기 호출 오류(있는 경우)는 컨텍스트에서 $ctx.error로 확인할 수 있습니다. 호출 오류에는 항상 $ctx.error.message$ctx.error.type 속성으로 액세스할 수 있는 메시지와 유형이 포함되어 있습니다. 응답 매핑 템플릿 호출 중 다음과 같은 3가지 방법으로 일부 결과를 처리할 수 있습니다.

  1. 데이터를 반환하여 호출 오류를 가립니다.

  2. 응답 매핑 템플릿 평가를 중단해 오류를 나타냅니다($util.error(...) 사용). 이 경우에는 데이터가 반환되지 않습니다.

  3. 오류를 추가하고($util.appendError(...) 사용) 데이터도 반환합니다.

DynamoDB 배치 작업을 사용해 위의 3가지 방법을 각각 시연해 보겠습니다!

DynamoDB 배치 작업

DynamoDB 배치 작업을 사용하면 배치를 부분적으로 완료할 수 있습니다. 즉, 요청된 항목 또는 키 중 일부가 처리되지 않은 상태로 남아 있을 수 있습니다. AWS AppSync가 배치를 완료할 수 없는 경우 처리되지 않은 항목 및 호출 오류가 컨텍스트에 따라 설정됩니다.

이 자습서 이전 단원에서 사용한 Query.getReadings 작업의 BatchGetItem 필드 구성을 사용하여 오류 처리를 구현하겠습니다. 이때, Query.getReadings 필드를 실행하는 동안 temperatureReadings DynamoDB 테이블에 프로비저닝된 처리량이 부족하다고 가정해 보겠습니다. DynamoDB는 배치의 나머지 요소를 처리하기 위해 AWS AppSync의 두 번째 시도 중에 ProvisionedThroughputExceededException을 발생시켰습니다.

다음 JSON은 DynamoDB 배치 호출 이후, 응답 매핑 템플릿이 평가되기 전 직렬화된 컨텍스트를 나타냅니다.

{ "arguments": { "sensorId": "1", "timestamp": "2018-02-01T17:21:05.000+08:00" }, "source": null, "result": { "data": { "temperatureReadings": [ null ], "locationReadings": [ { "lat": 47.615063, "long": -122.333551, "sensorId": "1", "timestamp": "2018-02-01T17:21:05.000+08:00" } ] }, "unprocessedKeys": { "temperatureReadings": [ { "sensorId": "1", "timestamp": "2018-02-01T17:21:05.000+08:00" } ], "locationReadings": [] } }, "error": { "type": "DynamoDB:ProvisionedThroughputExceededException", "message": "You exceeded your maximum allowed provisioned throughput for a table or for one or more global secondary indexes. (...)" }, "outErrors": [] }

컨텍스트에 대해서 알아야 할 몇 가지가 있습니다.

  • 호출 오류는 AWS AppSync에 의해 컨텍스트에서 $ctx.error로 설정되었으며 오류 유형은 DynamoDB:ProvisionedThroughputExceededException으로 설정되었습니다.

  • 오류가 있더라도 결과는 $ctx.result.data에서 테이블당 매핑됩니다.

  • 처리되지 않고 남아 있는 키는 $ctx.result.data.unprocessedKeys에서 확인할 수 있습니다. 여기서 AWS AppSync는 키(sensorId:1, timestamp:2018-02-01T17:21:05.000+08:00)를 사용해 항목을 검색할 수 없습니다. 테이블 처리량이 부족하기 때문입니다.

참고: BatchPutItem의 경우 $ctx.result.data.unprocessedItems입니다. BatchDeleteItem의 경우 $ctx.result.data.unprocessedKeys입니다.

이 오류를 세 가지 다른 방법으로 처리해 보겠습니다.

1. 호출 오류 가리기

호출 오류를 처리하지 않고 데이터를 반환하면 오류를 효과적으로 가려 주어진 GraphQL 필드에 대한 결과가 항상 성공입니다.

여기서 작성한 응답 매핑 템플릿은 알기 쉽고 결과 데이터에만 중점을 두고 있습니다.

응답 매핑 템플릿:

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

GraphQL 응답:

{ "data": { "getReadings": [ { "sensorId": "1", "timestamp": "2018-02-01T17:21:05.000+08:00", "lat": 47.615063, "long": -122.333551 }, { "sensorId": "1", "timestamp": "2018-02-01T17:21:05.000+08:00", "value": 85.5 } ] } }

데이터에 대해서만 실행되었으므로 오류 응답에 오류가 추가되지 않습니다.

2. 템플릿 실행 중단을 위한 오류 발생

클라이언트의 관점에서 부분 실패를 전체 실패로 간주해야 하는 경우 데이터가 반환되지 않도록 템플릿 실행을 중단할 수 있습니다. $util.error(...) 유틸리티 메서드가 정확하게 이러한 동작을 수행합니다.

응답 매핑 템플릿:

## there was an error let's mark the entire field ## as failed and do not return any data back in the response #if ($ctx.error) $util.error($ctx.error.message, $ctx.error.type, null, $ctx.result.data.unprocessedKeys) #end $util.toJson($ctx.result.data)

GraphQL 응답:

{ "data": { "getReadings": null }, "errors": [ { "path": [ "getReadings" ], "data": null, "errorType": "DynamoDB:ProvisionedThroughputExceededException", "errorInfo": { "temperatureReadings": [ { "sensorId": "1", "timestamp": "2018-02-01T17:21:05.000+08:00" } ], "locationReadings": [] }, "locations": [ { "line": 58, "column": 3 } ], "message": "You exceeded your maximum allowed provisioned throughput for a table or for one or more global secondary indexes. (...)" } ] }

일부 결과가 DynamoDB 배치 작업에서 반환될 수 있긴 하지만 오류를 일으키기로 선택합니다. 그러면 getReadings GraphQL 필드는 null이고 GraphQL 응답 오류 블록에 오류가 추가됩니다.

3. 오류를 추가하고 데이터 및 오류를 둘 다 반환

특정한 경우 사용자 경험을 개선하기 위해 애플리케이션에서는 일부 결과를 반환하고 클라이언트에게 처리되지 않은 항목이 있음을 알릴 수 있습니다. 그러면 클라이언트는 재시도를 수행하거나 오류를 최종 사용자에게 다시 번역할지 결정할 수 있습니다. $util.appendError(...)는 애플리케이션 디자이너가 템플릿 평가를 방해하지 않고 컨텍스트에 오류를 추가하도록 하여 이러한 동작을 가능하게 하는 유틸리티 메서드입니다. 템플릿 평가 후 AWS AppSync에서는 GraphQL 응답의 오류 블록에 오류를 추가해 모든 컨텍스트 오류를 처리합니다.

응답 매핑 템플릿:

#if ($ctx.error) ## pass the unprocessed keys back to the caller via the `errorInfo` field $util.appendError($ctx.error.message, $ctx.error.type, null, $ctx.result.data.unprocessedKeys) #end $util.toJson($ctx.result.data)

GraphQL 응답의 오류 블록 내에서 호출 오류 및 처리되지 않은 키 요소를 전달합니다. 아래 응답에 표시된 것처럼 getReadings 필드 역시 locationReadings 테이블의 일부 데이터를 반환합니다.

GraphQL 응답:

{ "data": { "getReadings": [ null, { "sensorId": "1", "timestamp": "2018-02-01T17:21:05.000+08:00", "value": 85.5 } ] }, "errors": [ { "path": [ "getReadings" ], "data": null, "errorType": "DynamoDB:ProvisionedThroughputExceededException", "errorInfo": { "temperatureReadings": [ { "sensorId": "1", "timestamp": "2018-02-01T17:21:05.000+08:00" } ], "locationReadings": [] }, "locations": [ { "line": 58, "column": 3 } ], "message": "You exceeded your maximum allowed provisioned throughput for a table or for one or more global secondary indexes. (...)" } ] }