条件式 - AWS AppSync GraphQL

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

条件式

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

AWS AppSync DynamoDB 関数を使用すると、PutItem、、UpdateItemおよび DeleteItemリクエストオブジェクトで条件式を指定でき、条件が失敗してオブジェクトが更新されなかった場合に従う戦略も許可されます。

例 1

以下の PutItem リクエストオブジェクトには条件式がありません。その結果、同じキーに対応する項目がすでにある場合でも、項目は DynamoDB に挿入され、それにより既存の項目が上書きされます。

import { util } from '@aws-appsync/utils'; export function request(ctx) { const { foo, bar, ...values} = ctx.args return { operation: 'PutItem', key: util.dynamodb.toMapValues({foo, bar}), attributeValues: util.dynamodb.toMapValues(values), }; }

例 2

次の PutItem オブジェクトには条件式があります。この場合、同じキーの項目が DynamoDB に存在しない場合のみ処理が成功します。

import { util } from '@aws-appsync/utils'; export function request(ctx) { const { foo, bar, ...values} = ctx.args return { operation: 'PutItem', key: util.dynamodb.toMapValues({foo, bar}), attributeValues: util.dynamodb.toMapValues(values), condition: { expression: "attribute_not_exists(id)" } }; }

デフォルトでは、条件チェックが失敗した場合、 AWS AppSync DynamoDB 関数はミューテーションにエラーを提供します。

ただし、 AWS AppSync DynamoDB 関数には、開発者が一般的なエッジケースを処理するのに役立ついくつかの追加機能があります。

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

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

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

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

条件を指定する

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

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

type ConditionCheckExpression = { expression: string; expressionNames?: { [key: string]: string}; expressionValues?: { [key: string]: any}; equalsIgnore?: string[]; consistentRead?: boolean; conditionalCheckFailedHandler?: { strategy: 'Custom' | 'Reject'; lambdaArn?: string; }; };

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

expression

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

expressionNames

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

expressionValues

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

残りのフィールドは、 AWS AppSync DynamoDB 関数に条件チェックの失敗を処理する方法を指示します。

equalsIgnore

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

consistentRead

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

conditionalCheckFailedHandler

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

strategy

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

Reject

ミューテーションは失敗し、GraphQL レスポンスにエラーが追加されます。

Custom

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

lambdaArn

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

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

条件チェックが失敗すると、 AWS AppSync DynamoDB 関数は、 util.appendErrorユーティリティを使用して、ミューテーションのエラーとオブジェクトの現在の値を渡すことができます。ただし、 AWS AppSync DynamoDB 関数には、開発者が一般的なエッジケースを処理するのに役立ついくつかの追加機能があります。

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

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

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

Flowchart showing process for transforming requests with mutation attempts and value checks.

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

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

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

    たとえば、PutItem リクエストオブジェクトが以下のようになっているとします。

    import { util } from '@aws-appsync/utils'; export function request(ctx) { const { id, name, version} = ctx.args return { operation: 'PutItem', key: util.dynamodb.toMapValues({foo, bar}), attributeValues: util.dynamodb.toMapValues({ name, version: version+1 }), condition: { expression: "version = :expectedVersion", expressionValues: util.dynamodb.toMapValues({':expectedVersion': version}), 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 関数はミューテーションのエラーを返します。

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

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

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

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

この関数レスポンスハンドラーは次のようになります。

import { util } from '@aws-appsync/utils'; export function response(ctx) { const { version, ...values } = ctx.result; const result = { ...values, theVersion: version }; if (ctx.error) { if (error) { return util.appendError(error.message, error.type, result, null); } } return result }

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

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

また、返されたオブジェクトのフィールドすべてが他のリゾルバーによって入力され、そのミューテーションが成功した場合、オブジェクトが 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) };