条件式 - AWS AppSync

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

条件式

PutItemUpdateItem、および DeleteItem の各 DynamoDB 処理を使用して DynamoDB のオブジェクトをミューテーションする場合、オプションで、処理を実行する前に、DynamoDB にある既存のオブジェクトの状態に基づいてリクエストが成功するかどうかを制御する条件式を指定することができます。

AWS AppSync DynamoDB リゾルバーではPutItem、、UpdateItem、および DeleteItemリクエストマッピングドキュメントで条件式を指定でき、条件が失敗してオブジェクトが更新されなかった場合に従う戦略も指定できます。

例 1

以下の PutItem マッピングドキュメントには条件式がありません。その結果、同じキーに対応する項目がすでにある場合でも、項目は DynamoDB に挿入され、それにより既存の項目が上書きされます。

{ "version" : "2017-02-28", "operation" : "PutItem", "key" : { "id" : { "S" : "1" } } }

例 2

次の PutItem マッピングドキュメントには条件式があります。この場合、同じキーの項目が DynamoDB に存在しない場合のみ処理が成功します。

{ "version" : "2017-02-28", "operation" : "PutItem", "key" : { "id" : { "S" : "1" } }, "condition" : { "expression" : "attribute_not_exists(id)" } }

デフォルトでは、条件チェックが失敗した場合、 AWS AppSync DynamoDB リゾルバーは GraphQL レスポンスの errorセクションの dataフィールドで、ミューテーションのエラーと DynamoDB のオブジェクトの現在の値を返します。ただし、 AWS AppSync DynamoDB リゾルバーには、デベロッパーが一般的なエッジケースを処理するのに役立ついくつかの追加機能があります。

  • AWS AppSync DynamoDB リゾルバーは、DynamoDB の現在の値が目的の結果と一致すると判断できる場合、オペレーションが成功したかのように扱います。

  • エラーを返す代わりに、カスタム Lambda 関数を呼び出して AWS AppSync DynamoDB リゾルバーが障害を処理する方法を決定するようにリゾルバーを設定できます。

これらの詳細については、「条件チェックでのエラーを処理する」セクションを参照してください。

DynamoDB 条件式の詳細については、DynamoDB ConditionExpressions ドキュメント を参照してください。

条件を指定する

PutItemUpdateItem、および DeleteItem の各リクエストマッピングドキュメントはすべて、オプションで condition セクションが指定できます。省略した場合、条件チェックは実行されません。指定した場合、処理が成功するには、条件が true となる必要があります。

condition セクションは以下の構造を持ちます。

"condition" : { "expression" : "someExpression" "expressionNames" : { "#foo" : "foo" }, "expressionValues" : { ":bar" : ... typed value }, "equalsIgnore" : [ "version" ], "consistentRead" : true, "conditionalCheckFailedHandler" : { "strategy" : "Custom", "lambdaArn" : "arn:..." } }

以下のフィールドに条件を指定します。

expression

更新式そのものを指定します。条件式を記述する方法の詳細については、DynamoDB ConditionExpressions ドキュメント を参照してください。このフィールドの指定は必須です。

expressionNames

式の属性名のプレースホルダーを示します。キー - 値のペアの形式になります。キーは expression で使用される名前のプレースホルダーに対応し、値は DynamoDB の項目の属性名と一致する文字列でなければなりません。このフィールドはオプションであり、expression で使用される式の属性名のプレースホルダーのみを入力します。

expressionValues

式の属性値のプレースホルダーを示します。キー - 値のペアの形式になります。キーは expression で使用される値のプレースホルダーに対応し、値は型付き値でなければなりません。「型付き値」を指定する方法の詳細については、「型システム (リクエストマッピング)」を参照してください。この指定は必須です。このフィールドはオプションであり、expression で使用される式の属性値のプレースホルダーのみを入力します。

残りのフィールドは、条件チェックの失敗を処理する方法を AWS AppSync DynamoDB リゾルバーに伝えます。

equalsIgnore

PutItem オペレーションの使用時に条件チェックが失敗すると、 AWS AppSync DynamoDB リゾルバーは DynamoDB の現在ある項目と、書き込みを試みた項目を比較します。これらが同じ場合、処理は成功として扱われます。equalsIgnore フィールドを使用して、その比較を実行するときに無視 AWS AppSync する属性のリストを指定できます。たとえば、唯一の違いが version 属性である場合、オペレーションは成功として扱われます。このフィールドはオプションです。

consistentRead

条件チェックが失敗すると、 は強力な整合性のある読み込みを使用して DynamoDB から項目の現在の値 AWS AppSync を取得します。このフィールドを使用して、代わりに結果整合性のある読み込みを使用するように AWS AppSync DynamoDB リゾルバーに指示できます。このフィールドはオプションであり、デフォルトは true です。

conditionalCheckFailedHandler

このセクションでは、 AWS AppSync DynamoDB リゾルバーが DynamoDB の現在の値と DynamoDB 予想される結果を比較した後に、条件チェックの失敗を処理する方法を指定できます。このセクションはオプションです。省略した場合、デフォルトの処理は Reject です。

strategy

AWS AppSync DynamoDB リゾルバーが DynamoDB の現在の値と予想される結果を比較した後に実行する戦略。このフィールドは必須であり、以下を値を設定できます。

Reject

このミューテーションは失敗し、ミューテーションに関するエラーが返されます。また、DynamoDB のオブジェクトの現在値が GraphQL レスポンスの error セクションの data フィールドで返されます。

Custom

AWS AppSync DynamoDB リゾルバーはカスタム Lambda 関数を呼び出して、条件チェックの失敗を処理する方法を決定します。strategy が に設定されている場合CustomlambdaArnフィールドには呼び出す Lambda 関数ARNの が含まれている必要があります。

lambdaArn

AWS AppSync DynamoDB リゾルバーが条件チェックARNの失敗を処理する方法を決定する、呼び出す Lambda 関数の 。このフィールドは、strategyCustom に設定されている場合のみ指定する必要があります。この機能の使用方法の詳細については、「条件チェックでのエラーを処理する」を参照してください。

条件チェックでのエラーを処理する

デフォルトでは、条件チェックが失敗すると、 AWS AppSync DynamoDB リゾルバーは GraphQL レスポンスの errorセクションの dataフィールドで、ミューテーションのエラーと DynamoDB 内のオブジェクトの現在の値を返します。ただし、 AWS AppSync DynamoDB リゾルバーには、デベロッパーが一般的なエッジケースを処理するのに役立ついくつかの追加機能があります。

  • AWS AppSync DynamoDB リゾルバーは、DynamoDB の現在の値が目的の結果と一致すると判断できる場合、オペレーションが成功したかのように扱います。

  • エラーを返す代わりに、カスタム Lambda 関数を呼び出して AWS AppSync DynamoDB リゾルバーが障害を処理する方法を決定するようにリゾルバーを設定できます。

このプロセスのフローチャートは次のとおりです。

必要な結果をチェックする

条件チェックが失敗すると、 AWS AppSync DynamoDB リゾルバーは GetItem DynamoDB リクエストを実行して、DynamoDB から項目の現在の値を取得します。デフォルトでは、強力な整合性のある読み込みを使用しますが、condition ブロックの consistentRead フィールドを使用してこれを設定し、この値を期待した結果と比較することができます。

  • PutItem オペレーションでは、 AWS AppSync DynamoDB リゾルバーは、現在の値を書き込みを試みた値と比較します。ただし、比較equalsIgnoreから にリストされている属性は除きます。項目が同じ場合は、処理は成功として扱われ、DynamoDB から取得された項目が返されます。それ以外の場合は、設定された処理に従います。

    たとえば、PutItem リクエストマッピングドキュメントが以下のようになっているとします。

    { "version" : "2017-02-28", "operation" : "PutItem", "key" : { "id" : { "S" : "1" } }, "attributeValues" : { "name" : { "S" : "Steve" }, "version" : { "N" : 2 } }, "condition" : { "expression" : "version = :expectedVersion", "expressionValues" : { ":expectedVersion" : { "N" : 1 } }, "equalsIgnore": [ "version" ] } }

    現在、DynamoDB にある項目は以下のようになりました。

    { "id" : { "S" : "1" }, "name" : { "S" : "Steve" }, "version" : { "N" : 8 } }

    AWS AppSync DynamoDB リゾルバーは、書き込もうとした項目を現在の値と比較し、唯一の違いが version フィールドであったことを確認しますが、 versionフィールドを無視するように設定されているため、オペレーションは成功として扱われ、DynamoDB から取得した項目を返します。

  • DeleteItem オペレーションでは、 AWS AppSync DynamoDB リゾルバーは項目が DynamoDB から返されたことを確認します。項目が返されなかった場合、処理は成功として扱われます。それ以外の場合は、設定された処理に従います。

  • UpdateItem オペレーションの場合、 AWS AppSync DynamoDB リゾルバーには、現在 DynamoDB にある項目が期待される結果と一致するかどうかを判断するのに十分な情報がないため、設定された戦略に従います。

DynamoDB のオブジェクトの現在の状態が予想される結果と異なる場合、 AWS AppSync DynamoDB リゾルバーは設定された戦略に従ってミューテーションを拒否するか、Lambda 関数を呼び出して次に何をすべきかを決定します。

「reject」の戦略に従う

Reject 戦略に従うと、 AWS AppSync DynamoDB リゾルバーはミューテーションのエラーを返し、DynamoDB のオブジェクトの現在の値は GraphQL レスポンスの errorセクションの dataフィールドにも返されます。DynamoDB から返された項目がレスポンスマッピングテンプレートにより入力され、クライアントが期待する形式に変換されます。また、選択設定によりフィルタ処理も行われます。

たとえば、次のミューテーションリクエストが指定されたとします。

mutation { updatePerson(id: 1, name: "Steve", expectedVersion: 1) { Name theVersion } }

DynamoDB から返された項目が以下のようになっているとします。

{ "id" : { "S" : "1" }, "name" : { "S" : "Steve" }, "version" : { "N" : 8 } }

また、レスポンスマッピングテンプレートは以下のようになっているとします。

{ "id" : $util.toJson($context.result.id), "Name" : $util.toJson($context.result.name), "theVersion" : $util.toJson($context.result.version) }

GraphQL レスポンスは以下のようになります。

{ "data": null, "errors": [ { "message": "The conditional request failed (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ConditionalCheckFailedException; Request ID: ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ)" "errorType": "DynamoDB:ConditionalCheckFailedException", "data": { "Name": "Steve", "theVersion": 8 }, ... } ] }

また、返されたオブジェクトのフィールドすべてが他のリゾルバーによって入力され、そのミューテーションが成功した場合、オブジェクトが error セクションに返されたときに、それらのフィールドは解決されません。

「custom」戦略に従う

Custom 戦略に従うと、 AWS AppSync DynamoDB リゾルバーは Lambda 関数を呼び出して、次に何をすべきかを決定します。Lambda 関数は以下のオプションのいずれかを選択します。

  • ミューテーション を reject する これにより、前のセクションで説明したように、 AWS AppSync DynamoDB リゾルバーは設定された戦略が であるかのように動作しReject、ミューテーションのエラーと DynamoDB 内のオブジェクトの現在の値を返します。

  • ミューテーション を discard する これにより、 AWS AppSync DynamoDB リゾルバーは条件チェックの失敗を黙って無視し、DynamoDB の 値を返します。

  • ミューテーション を retry する これにより、 AWS AppSync DynamoDB リゾルバーは新しいリクエストマッピングドキュメントでミューテーションを再試行するように指示されます。

Lambda 呼び出しリクエスト

AWS AppSync DynamoDB リゾルバーは、 で指定された Lambda 関数を呼び出しますlambdaArn。また、データソースに設定されたものと同じ service-role-arn を使用します。呼び出しのペイロードは以下の構造を持ちます。

{ "arguments": { ... }, "requestMapping": {... }, "currentValue": { ... }, "resolver": { ... }, "identity": { ... } }

各フィールドの定義は以下のようになります。

arguments

GraphQL ミューテーションの引数です。これは、$context.arguments のリクエストマッピングドキュメントで使用できる引数と同じです。

requestMapping

この処理のリクエストマッピングドキュメントです。

currentValue

DynamoDB のオブジェクトの現在値。

resolver

リ AWS AppSync ゾルバーに関する情報。

identity

呼び出し元に関する情報。これは、$context.identity のリクエストマッピングドキュメントで使用できる識別情報と同じです。

完全なペイロードの例を次に示します。

{ "arguments": { "id": "1", "name": "Steve", "expectedVersion": 1 }, "requestMapping": { "version" : "2017-02-28", "operation" : "PutItem", "key" : { "id" : { "S" : "1" } }, "attributeValues" : { "name" : { "S" : "Steve" }, "version" : { "N" : 2 } }, "condition" : { "expression" : "version = :expectedVersion", "expressionValues" : { ":expectedVersion" : { "N" : 1 } }, "equalsIgnore": [ "version" ] } }, "currentValue": { "id" : { "S" : "1" }, "name" : { "S" : "Steve" }, "version" : { "N" : 8 } }, "resolver": { "tableName": "People", "awsRegion": "us-west-2", "parentType": "Mutation", "field": "updatePerson", "outputType": "Person" }, "identity": { "accountId": "123456789012", "sourceIp": "x.x.x.x", "user": "AIDAAAAAAAAAAAAAAAAAA", "userArn": "arn:aws:iam::123456789012:user/appsync" } }

Lambda 呼び出しレスポンス

Lambda 関数は呼び出しペイロードを検査し、ビジネスロジックを適用して、 AWS AppSync DynamoDB リゾルバーが障害をどのように処理するかを決定できます。条件チェックで検出されたエラーを処理するために、以下の 3 つのオプションが指定できます。

  • ミューテーション を reject する このオプションのレスポンスペイロードは次の構造を持ちます。

    { "action": "reject" }

    これにより、 AWS AppSync DynamoDB リゾルバーは設定された戦略が であるかのように動作しReject、上記のセクションで説明したように、ミューテーションのエラーと DynamoDB 内のオブジェクトの現在の値を返すように指示されます。

  • ミューテーション を discard する このオプションのレスポンスペイロードは次の構造を持ちます。

    { "action": "discard" }

    これにより、 AWS AppSync DynamoDB リゾルバーは条件チェックの失敗を黙って無視し、DynamoDB の 値を返します。

  • ミューテーション を retry する このオプションのレスポンスペイロードは次の構造を持ちます。

    { "action": "retry", "retryMapping": { ... } }

    これにより、 AWS AppSync DynamoDB リゾルバーは新しいリクエストマッピングドキュメントでミューテーションを再試行するように指示されます。retryMapping セクションの構造は DynamoDB の処理によって異なり、その処理の完全なリクエストマッピングドキュメントのサブセットとなります。

    PutItem の場合、retryMapping セクションは次の構造を持ちます。attributeValues フィールドの説明については、「」を参照してくださいPutItem

    { "attributeValues": { ... }, "condition": { "equalsIgnore" = [ ... ], "consistentRead" = true } }

    UpdateItem の場合、retryMapping セクションは次の構造を持ちます。update セクションの説明については、「」を参照してくださいUpdateItem

    { "update" : { "expression" : "someExpression" "expressionNames" : { "#foo" : "foo" }, "expressionValues" : { ":bar" : ... typed value } }, "condition": { "consistentRead" = true } }

    DeleteItem の場合、retryMapping セクションは次の構造を持ちます。

    { "condition": { "consistentRead" = true } }

    使用する別の処理やキーを指定する方法はありません。 AWS AppSync DynamoDB リゾルバーは、同じオブジェクトに対して同じオペレーションの再試行のみを許可します。また、condition セクションでは conditionalCheckFailedHandler は指定できません。再試行が失敗した場合、 AWS AppSync DynamoDB リゾルバーは Reject戦略に従います。

以下は、失敗した PutItem リクエストを処理する Lambda 関数の例です。ビジネスロジックは呼び出し元を調べます。呼び出し元が jeffTheAdmin の場合は、リクエストを再試行して、現在 DynamoDB にある項目の versionexpectedVersion を更新します。それ以外の場合は、ミューテーションを拒否します。

exports.handler = (event, context, callback) => { console.log("Event: "+ JSON.stringify(event)); // Business logic goes here. var response; if ( event.identity.user == "jeffTheAdmin" ) { response = { "action" : "retry", "retryMapping" : { "attributeValues" : event.requestMapping.attributeValues, "condition" : { "expression" : event.requestMapping.condition.expression, "expressionValues" : event.requestMapping.condition.expressionValues } } } response.retryMapping.attributeValues.version = { "N" : event.currentValue.version.N + 1 } response.retryMapping.condition.expressionValues[':expectedVersion'] = event.currentValue.version } else { response = { "action" : "reject" } } console.log("Response: "+ JSON.stringify(response)) callback(null, response) };