本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
當您使用 PutItem
、 UpdateItem
和 DynamoDB 操作來變更 DeleteItem
DynamoDB 中的物件時,您可以選擇指定條件表達式,以根據在執行操作之前已在 DynamoDB 中建立的物件狀態來控制請求是否成功。
The 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 函數提供一些額外的功能,以協助開發人員處理一些常見的邊緣案例:
-
If AWS AppSync DynamoDB 函數可以判斷 DynamoDB 中的目前值是否符合所需的結果,它會將操作視為成功。
-
您可以設定函數來叫用自訂 Lambda 函數,以決定 AWS AppSync DynamoDB 函數應如何處理失敗,而不是傳回錯誤。
這些會在處理條件檢查失敗一節中詳細說明。
如需 DynamoDB 條件表達式的詳細資訊,請參閱 DynamoDB ConditionExpressions 文件。
指定條件
PutItem
、 UpdateItem
和 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
-
表達式屬性名稱預留位置的替代,形式為索引鍵值對。索引鍵對應至表達式中使用的名稱預留位置,且值必須是對應於 DynamoDB 中項目屬性名稱的字串。此欄位為選用的,應只能填入於表達式中所用表達式屬性名稱預留位置的替代。
-
expressionValues
-
表達式屬性值預留位置的替代,形式為索引值對。鍵對應用於表達式的值預留位置,值必須是類型值。如需如何指定「輸入值」的詳細資訊,請參閱類型系統 (請求映射)。此必須指定。此欄位為選用的,應只能填入用於表達式中表達式屬性值預留位置的替代。
其餘欄位會告知 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 中的目前值與預期結果進行比較後,如何處理條件檢查失敗。此區段為選用。若省略,則會預設為
Reject
策略。-
strategy
-
在將 DynamoDB 中的目前值與預期結果進行比較之後, AWS AppSync DynamoDB 函數採用的策略。 DynamoDB 此欄位為必填,且採用下列可能值:
-
Reject
-
變動失敗,且錯誤會新增至 GraphQL 回應。
-
Custom
-
The AWS AppSync DynamoDB 函數會叫用自訂 Lambda 函數,以決定如何處理條件檢查失敗。當
strategy
設定為Custom
,lambdaArn
欄位必須包含要叫用 Lambda 函數的 ARN。
-
-
lambdaArn
-
要叫用之 Lambda 函數的 ARN,其決定 AWS AppSync DynamoDB 函數應如何處理條件檢查失敗。只有在
strategy
設定為Custom
時,此欄位才必須指定。如需如何使用此功能的詳細資訊,請參閱處理條件檢查失敗。
-
處理條件檢查失敗
當條件檢查失敗時, AWS AppSync DynamoDB 函數可以使用 util.appendError
公用程式傳遞 變動的錯誤和物件的目前值。不過, AWS AppSync DynamoDB 函數提供一些額外的功能,以協助開發人員處理一些常見的邊緣案例:
-
If AWS AppSync DynamoDB 函數可以判斷 DynamoDB 中的目前值是否符合所需的結果,它會將操作視為成功。
-
您可以設定函數來叫用自訂 Lambda 函數,以決定 AWS AppSync DynamoDB 函數應如何處理失敗,而不是傳回錯誤。
此程序的流程圖為:

檢查所需結果
當條件檢查失敗時, 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 } }
The AWS AppSync DynamoDB 函數會將嘗試寫入的項目與目前值進行比較,查看唯一差異是
version
欄位,但因為它設定為忽略version
欄位,它會將操作視為成功,並傳回從 DynamoDB 擷取的項目。 -
對於
DeleteItem
操作, AWS AppSync DynamoDB 函數會檢查以確認項目已從 DynamoDB 傳回。如果沒有項目傳回,則操作視為成功。否則,其將按照設定的策略。 -
對於
UpdateItem
操作, AWS AppSync DynamoDB 函數沒有足夠的資訊來判斷目前 DynamoDB 中的項目是否符合預期結果,因此遵循設定的策略。
如果 DynamoDB 中物件的目前狀態與預期結果不同, AWS AppSync DynamoDB 函數會遵循已設定的策略,以拒絕變動或叫用 Lambda 函數來決定接下來要做什麼。
遵循「拒絕」策略
遵循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
策略時, AWS AppSync DynamoDB 函數會叫用 Lambda 函數來決定接下來要做什麼。Lambda 函數會選擇下列其中一個選項:
-
reject
變動。這可讓 AWS AppSync DynamoDB 函數表現得好像已設定的策略是Reject
,傳回 DynamoDB 中物件的變動錯誤和目前值,如上一節所述。 -
discard
變動。這可讓 AWS AppSync DynamoDB 函數以無提示方式忽略條件檢查失敗,並在 DynamoDB 中傳回值。 -
retry
變動。這會告知 AWS AppSync DynamoDB 函數使用新的請求物件重試變動。
Lambda 叫用要求
The 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 函數應如何處理失敗。處理條件檢查失敗有三個選項:
-
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
策略。
此為 Lambda 函數處理失敗 PutItem
要求的範例。商業邏輯的重點是發起人為何。如果是由 提出jeffTheAdmin
,則會重試請求,expectedVersion
並從目前 DynamoDB 中的項目更新 version
和 。否則,它會拒絕變動。
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)
};