での DynamoDB バッチオペレーションの使用 AWS AppSync - AWS AppSync

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

での DynamoDB バッチオペレーションの使用 AWS AppSync

注記

現在、主に APPSYNC_JS ランタイムとそのドキュメントをサポートしています。APPSYNC_JS ランタイムとそのガイドをここで使用することを検討してください。

AWS AppSync は、単一のリージョン内の 1 つ以上のテーブルで Amazon DynamoDB バッチオペレーションの使用をサポートします。サポートされている処理は、BatchGetItemBatchPutItem、および BatchDeleteItem です。でこれらの機能を使用すると AWS AppSync、次のようなタスクを実行できます。

  • 単一クエリでキーのリストを渡し、テーブルからの結果を返す

  • 単一クエリで 1 つ以上のテーブルからレコードを読み取る

  • 1 つ以上のテーブルに一連のレコードを書き込む

  • 関連のある複数のテーブルのレコードを状況に応じて書き込みまたは削除

で DynamoDB でバッチオペレーションを使用すること AWS AppSync は、バックエンドオペレーションとテーブル構造について、もう少し深く考え、知識を身に付ける高度な手法です。さらに、 のバッチオペレーション 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 に対して取得するよう設定されたデータソースは、設定を単純にするために 1 つのテーブルのみ指定されます。したがって、単一のリゾルバーで複数のテーブルに対してバッチ処理を実行する場合、これはより高度なタスクであり、リゾルバーが利用するすべてのテーブルへのアクセスをデータソースのロールに許可する必要があります。これは、上記の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/*" ] } ] }

1 つのテーブルのバッチ処理

警告

BatchPutItem および BatchDeleteItem は、競合の検出と解決とともに使用する場合はサポートされていません。これらの設定は、起こり得るエラーを防ぐために無効にする必要があります。

以下の例では、Posts という名前の単一のテーブルがあり、バッチ処理を使用してこれに項目を追加または削除するとします。次のスキーマを使用して、クエリに のリストを渡すことに注意してくださいIDs。

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 として context オブジェクトに追加されています。

$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 として context オブジェクトに追加されます。

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

次に、コンソールの AWS AppSyncクエリページに戻り、次のbatchGet クエリを実行します。

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

これは、以前に追加した 2 つの id 値の結果を返します。値が nullid に対して 3 値が返っていることに注意してください。これは、その値に対応するレコードが 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 として context オブジェクトに追加されます。

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

コンソールの AWS AppSyncクエリページに戻り、次のbatchDeleteミューテーションを実行します。

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

id12 のレコードが削除されます。以前に使用した batchGet() クエリを再実行すると、これらは null を返します。

複数テーブルのバッチ処理

警告

BatchPutItem および BatchDeleteItem は、競合の検出と解決とともに使用する場合はサポートされていません。これらの設定は、起こり得るエラーを防ぐために無効にする必要があります。

AWS AppSync では、テーブル間でバッチオペレーションを実行することもできます。より複雑なアプリケーションを作成しましょう。Pet Health アプリを作成するとします。これは、センサーによりペットの場所と体温を報告します。センサーは電池により動作し、数分ごとにネットワークへの接続を試みます。センサーが接続を確立すると、センサーは測定値を に送信します AWS AppSync API。その後、データの分析がトリガーされ、ペットの飼い主にダッシュボードが表示されます。センサーとバックエンドのデータストア間のやり取りの作成について考えてみましょう。

前提条件として、まず 2 つの 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() を使用することを推奨します。

リゾルバーを保存し、 AWS AppSync コンソールのクエリページに移動します。センサーの読み取り値をいくつか送信してみましょう!

次のミューテーションを実行します。

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 } } }

1 つのミューテーションで 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)

リゾルバーを保存し、 AWS AppSync コンソールのクエリページに移動します。では、いくつかのセンサーの読み取り値を削除しましょう!

次のミューテーションを実行します。

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 つの読み取り値が locationReadingsおよび temperatureReadingsテーブルから削除されたことを確認します。

BatchGetItem - 読み取り値の取得

Pet Health アプリのもう 1 つの一般的な処理として、特定の時刻にセンサーの読み取り値を取得します。スキーマの Query.getReadings GraphQL フィールドにリゾルバーをアタッチしましょう。[Attach (アタッチ)] を選択し、次の画面で、このチュートリアルの最初で作成したのと同じ 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)

リゾルバーを保存し、 AWS AppSync コンソールのクエリページに移動します。では、センサーの読み取り値を取得しましょう!

次のクエリを実行します。

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 } } }

を使用した DynamoDB バッチオペレーションの使用を正常に実証しました AWS AppSync。

エラー処理

では AWS AppSync、データソースオペレーションが部分的な結果を返すことがあります。部分的な結果という用語は、処理の出力がいくつかのデータと 1 つのエラーで構成されていることを表す場合に使用します。エラー処理は本質的にアプリケーション固有であるため、 AWS AppSync はレスポンスマッピングテンプレートでエラーを処理する機会を提供します。リゾルバーの呼び出しエラーがある場合、これは context から $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 ために によって 2 回目の試行ProvisionedThroughputExceededException時に を提起しました。

以下は、DynamoDB バッチ呼び出し後、レスポンスマッピングテンプレートが評価される前のシリアル化されたコンテキストJSONを表します。

{ "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": [] }

context に関する注意事項がいくつかあります。

  • 呼び出しエラーは $ctx.errorによって のコンテキストに設定され AWS AppSync、エラータイプは DynamoDB :ProvisionedThroughputExceededException に設定されています。

  • エラーが存在していても、結果はテーブルごとに $ctx.result.data にマッピングされます。

  • 未処理のキーは $ctx.result.data.unprocessedKeys でアクセス可能です。ここでは、テーブルスループットが不十分なため、キー (sensorId:1、タイムスタンプ:2018-02-01T17:21:05.000+08:00) を持つ項目を取得 AWS AppSync できませんでした。

注意 : BatchPutItem の場合、これは $ctx.result.data.unprocessedItems です。BatchDeleteItem の場合、これは $ctx.result.data.unprocessedKeys です。

3 つの異なる方法でこのエラーを処理しましょう。

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 レスポンスの errors ブロックにエラーが追加されるようにします。

3. エラーを付加してデータとエラーの両方を返す

場合によっては、より優れたユーザーエクスペリエンスを提供するために、アプリケーションから部分的な結果を返すとともに、クライアントに未処理の項目を通知することができます。クライアントでは、再試行を実装することも、エラーを変換してエンドユーザーに通知することもできます。$util.appendError(...) はこの動作を可能とするユーティリティメソッドであり、アプリケーションの設計者は、テンプレートの評価を妨げることなく、context にエラーを付加できます。テンプレートを評価した後、 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 レスポンスのエラーブロック内で、呼び出しエラーと unprocessedKeys 要素の両方を転送しました。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. (...)" } ] }