条件表达式 - AWS AppSync

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

条件表达式

在您使用 PutItemUpdateItemDeleteItem DynamoDB 操作变更 DynamoDB 中的对象时,您可以选择指定一个条件表达式,以根据执行操作之前 DynamoDB 中的已有对象状态控制请求是否应成功。

D AWS AppSync ynamoDB 解析器允许PutItemUpdateItemDeleteItem和请求映射文档中指定条件表达式,还允许在条件失败且对象未更新时遵循的策略。

示例 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)" } }

默认情况下,如果条件检查失败,D AWS AppSync ynamoDB 解析器会在 GraphQL 响应部分的字段中返回变异错误和 DynamoDB 中对象的data当前值。error但是, AWS AppSync DynamoDB 解析器提供了一些其他功能来帮助开发人员处理一些常见的边缘情况:

  • 如果 D AWS AppSync ynamoDB 解析器可以确定 DynamoDB 中的当前值与所需结果相匹配,则它会将该操作视为成功了。

  • 您可以将解析器配置为调用自定义 Lambda 函数来决定 Dynam AWS AppSync oDB 解析器应如何处理故障,而不是返回错误。

处理条件检查失败一节中更详细地介绍了这些内容。

有关 DynamoDB 条件表达式的更多信息,请参阅 DynamoDB 文档。 ConditionExpressions

指定条件

PutItemUpdateItemDeleteItem 请求映射文档都允许指定可选的 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操作时条件检查失败时,D AWS AppSync ynamoDB 解析器会将当前在 DynamoDB 中的项目与其尝试写入的项目进行比较。如果两者相同,则它会将操作视为已成功。您可以使用该equalsIgnore字段来指定在执行比较时 AWS AppSync 应忽略的属性列表。例如,如果唯一的区别是 version 属性,则会将操作视为成功。该字段是可选的。

consistentRead

当条件检查失败时,使用强一致性读取从 DynamoDB AWS AppSync 获取项目的当前值。您可以使用此字段告诉 AWS AppSync DynamoDB 解析器改用最终一致性读取。该字段是可选的,默认值为 true

conditionalCheckFailedHandler

本节允许您指定 D AWS AppSync ynamoDB 解析器在将 DynamoDB 中的当前值与预期结果进行比较后如何处理条件检查失败。此部分是可选的。如果省略,它默认为 Reject 策略。

strategy

AWS AppSync DynamoDB 解析器在将 DynamoDB 中的当前值与预期结果进行比较后采取的策略。该字段为必填字段,有以下可能的值:

Reject

变更失败,将返回变更错误,并在 GraphQL 响应 error 部分的 data 字段中返回 DynamoDB 中的对象的当前值。

Custom

AWS AppSync DynamoDB 解析器调用自定义 Lambda 函数来决定如何处理条件检查失败。当设置strategy为时Custom,该lambdaArn字段必须包含要调用的 ARN Lambda 函数的。

lambdaArn

要调用的 Lambda 函数,用于确定 Dynamo AWS AppSync DB 解析器应如何处理条件检查失败。ARN当 strategy 设置为 Custom 时,必须指定该字段。有关如何使用该功能的更多信息,请参阅处理条件检查失败

处理条件检查失败

默认情况下,当条件检查失败时,D AWS AppSync ynamoDB 解析器会在 GraphQL 响应部分的字段中返回变异错误和 DynamoDB 中对象的当前值。data error但是, AWS AppSync DynamoDB 解析器提供了一些其他功能来帮助开发人员处理一些常见的边缘情况:

  • 如果 D AWS AppSync ynamoDB 解析器可以确定 DynamoDB 中的当前值与所需结果相匹配,则它会将该操作视为成功了。

  • 您可以将解析器配置为调用自定义 Lambda 函数来决定 Dynam AWS AppSync oDB 解析器应如何处理故障,而不是返回错误。

此过程的流程图为:

检查所需的结果

当条件检查失败时,D AWS AppSync ynamoDB 解析器会执行 DynamoDB 请求GetItem,以从 DynamoDB 获取项目的当前值。默认情况下,它将使用强一致性读取,但这可以使用 condition 数据块中的 consistentRead 字段进行配置,并将当前值与预期结果进行比较:

  • 对于该PutItem操作,D AWS AppSync ynamoDB 解析器会将当前值与其尝试写入的值进行比较,不包括比较中列出的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 } }

    D AWS AppSync ynamoDB 解析器会将其尝试写入的项目与当前值进行比较,发现唯一的区别在于字段,但是由于配置为忽略versionversion该字段,因此它会将操作视为成功并返回从 DynamoDB 检索到的项目。

  • 对于该DeleteItem操作, AWS AppSync DynamoDB 解析器会进行检查以验证是否已从 DynamoDB 返回了项目。如果没有返回项目,它会将该操作视为已成功。否则,它将遵循所配置的策略。

  • 对于该UpdateItem操作,D AWS AppSync ynamoDB 解析器没有足够的信息来确定 DynamoDB 中当前的项目是否与预期结果匹配,因此遵循了配置的策略。

如果 DynamoDB 中对象的当前状态与预期结果不同,则 D AWS AppSync ynamoDB 解析器将遵循配置的策略,拒绝变更或调用 Lambda 函数来确定下一步要做什么。

遵循“reject”策略

遵循该Reject策略时,D AWS AppSync ynamoDB 解析器会返回变异错误,DynamoDB 中对象的当前值也会在 GraphQL 响应部分的字段中返回。data error从 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 变更。这会告诉 D AWS AppSync ynamoDB 解析器像配置的策略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 函数可以检查调用负载并应用任何业务逻辑来决定 DynamoDB 解析器应如何处理 AWS AppSync 故障。有三种选项可用于处理条件检查失败:

  • reject 变更。此选项的响应负载必须具有此结构:

    { "action": "reject" }

    这告诉 D AWS AppSync ynamoDB 解析器表现得像配置的策略Reject一样,返回变异错误和 DynamoDB 中对象的当前值,如上一节所述。

  • discard 变更。此选项的响应负载必须具有此结构:

    { "action": "discard" }

    这会告诉 AWS AppSync DynamoDB 解析器以静默方式忽略条件检查失败,并在 DynamoDB 中返回该值。

  • retry 变更。此选项的响应负载必须具有此结构:

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

    这会告诉 AWS AppSync DynamoDB 解析器使用新的请求映射文档重试变更。retryMapping 部分的结构取决于 DynamoDB 操作,并且是该操作的完整请求映射文档的子集。

    对于 PutItemretryMapping 部分具有以下结构。有关该attributeValues字段的说明,请参见PutItem

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

    对于 UpdateItemretryMapping 部分具有以下结构。有关该update部分的说明,请参见UpdateItem

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

    对于 DeleteItemretryMapping 部分具有以下结构。

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

    无法指定要使用的不同的操作或键。 AWS AppSync DynamoDB 解析器仅允许对同一个对象重试相同的操作。另外,condition 部分不允许指定 conditionalCheckFailedHandler。如果重试失败,则 Dynamo AWS AppSync DB 解析器将遵循该策略。Reject

在下面的示例中,Lambda 函数处理失败的 PutItem 请求。业务逻辑将查看进行调用的用户。如果调用是由 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) };