View a markdown version of this page

Expressões de condição - AWS AppSync GraphQL

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Expressões de condição

Quando objetos sofrem mutação no DynamoDB usando as operações PutItem, UpdateItem e DeleteItem do DynamoDB, opcionalmente, é possível especificar uma expressão de condição que controla se a solicitação deve ser bem-sucedida ou não, com base no estado do objeto que já está no DynamoDB antes que a operação seja realizada.

A função do AWS AppSync DynamoDB permite que uma expressão de condição seja especificada em PutItemUpdateItem, e DeleteItem solicite objetos, além de uma estratégia a ser seguida se a condição falhar e o objeto não for atualizado.

Exemplo 1

O objeto de solicitação PutItem a seguir não tem uma expressão de condição. Como resultado, ele coloca um item no DynamoDB mesmo se um item com a mesma chave já existir, sobrescrevendo o item existente.

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), }; }

Exemplo 2

O seguinte objeto PutItem possui uma expressão de condição que permite que a operação seja bem-sucedida somente se um item com a mesma chave não existir no 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)" } }; }

Por padrão, se a verificação da condição falhar, a função do AWS AppSync DynamoDB fornecerá um erro para a mutação.

No entanto, a função do AWS AppSync DynamoDB oferece alguns recursos adicionais para ajudar os desenvolvedores a lidar com alguns casos extremos comuns:

  • Se as funções AWS AppSync do DynamoDB puderem determinar que o valor atual no DynamoDB corresponde ao resultado desejado, elas tratarão a operação como se tivesse sido bem-sucedida de qualquer maneira.

  • Em vez de retornar um erro, você pode configurar a função para invocar uma função personalizada do Lambda para decidir como a função do AWS AppSync DynamoDB deve lidar com a falha.

Isso é descrito com mais detalhes na seção Tratamento de uma falha de verificação da condição.

Para obter mais informações sobre as expressões de condições do DynamoDB, consulte a documentação do DynamoDB ConditionExpressions .

Especificação de uma condição

Os objetos da solicitação PutItem, UpdateItem e DeleteItem permitem que uma seção condition opcional seja especificada. Se omitida, nenhuma verificação de condição é feita. Se especificada, a condição deve ser verdadeira para que a operação seja bem-sucedida.

A seção condition tem a seguinte estrutura:

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

Os campos a seguir especificam a condição:

expression

A própria expressão de atualização. Para obter mais informações sobre como escrever expressões condicionais, consulte a documentação do DynamoDB. ConditionExpressions Esse campo deve ser especificado.

expressionNames

As substituições para espaços reservados de nome do atributo da expressão, na forma de pares de chave/valor. A chave corresponde a um espaço reservado de nome usado na expressão e o valor deve ser uma string que corresponde ao nome do atributo do item no DynamoDB. Esse campo é opcional e deve ser preenchido apenas por substituições para espaços reservados de nome do atributo da expressão usados na expressão.

expressionValues

As substituições para espaços reservados de valor do atributo da expressão, na forma de pares chave-valor. A chave corresponde a um espaço reservado de valor usado na expressão e o valor deve ser um valor digitado. Para obter mais informações sobre como especificar um "valor digitado", consulte Sistema de tipo (Mapeamento de solicitação). Isso deve ser especificado. Esse campo é opcional e deve ser preenchido apenas por substituições para espaços reservados de valor do atributo da expressão usados na expressão.

Os campos restantes informam à função do AWS AppSync DynamoDB como lidar com uma falha na verificação de condição:

equalsIgnore

Quando uma verificação de condição falha ao usar a PutItem operação, a função do AWS AppSync DynamoDB compara o item atualmente no DynamoDB com o item que ela tentou gravar. Se forem os mesmos, ele tratará a operação como bem-sucedida. Você pode usar o equalsIgnore campo para especificar uma lista de atributos que AWS AppSync devem ser ignorados ao realizar essa comparação. Por exemplo, se a única diferença era um atributo version, ele trata a operação como bem-sucedida. Esse campo é opcional.

consistentRead

Quando uma verificação de condição falha, AWS AppSync obtém o valor atual do item do DynamoDB usando uma leitura fortemente consistente. Você pode usar esse campo para dizer à função do AWS AppSync DynamoDB que, em vez disso, use uma leitura eventualmente consistente. Esse campo é opcional e usa como padrão true.

conditionalCheckFailedHandler

Esta seção permite especificar como a função do AWS AppSync DynamoDB trata uma falha na verificação de condição depois de comparar o valor atual no DynamoDB com o resultado esperado. Esta seção é opcional. Se omitida, o padrão será uma estratégia de Reject.

strategy

A estratégia que a função do AWS AppSync DynamoDB adota depois de comparar o valor atual no DynamoDB com o resultado esperado. Esse campo é obrigatório e tem os valores possíveis a seguir:

Reject

A mutação falha, e um erro é adicionado à resposta do GraphQL.

Custom

A função do AWS AppSync DynamoDB invoca uma função personalizada do Lambda para decidir como lidar com a falha na verificação da condição. Quando a strategy estiver definida como Custom, o campo lambdaArn deve conter o ARN da função do Lambda a ser invocada.

lambdaArn

O ARN da função Lambda a ser invocada que determina como a função do AWS AppSync DynamoDB deve lidar com a falha na verificação da condição. Esse campo deve ser especificado somente quando strategy for definida como Custom. Para obter mais informações sobre como usar esse atributo, consulte Tratamento de uma falha de verificação da condição.

Tratamento de uma falha de verificação da condição

Quando uma verificação de condição falha, a função do AWS AppSync DynamoDB pode transmitir o erro da mutação e do valor atual do objeto usando o utilitário. util.appendError No entanto, a função do AWS AppSync DynamoDB oferece alguns recursos adicionais para ajudar os desenvolvedores a lidar com alguns casos extremos comuns:

  • Se as funções AWS AppSync do DynamoDB puderem determinar que o valor atual no DynamoDB corresponde ao resultado desejado, elas tratarão a operação como se tivesse sido bem-sucedida de qualquer maneira.

  • Em vez de retornar um erro, você pode configurar a função para invocar uma função personalizada do Lambda para decidir como a função do AWS AppSync DynamoDB deve lidar com a falha.

O fluxograma para esse processo é:

Fluxograma mostrando o processo de tentativa de mutação com pontos de decisão para sucesso, estratégia e ação.

Verificação do resultado desejado

Quando a verificação da condição falha, a função do AWS AppSync DynamoDB executa uma solicitação do GetItem DynamoDB para obter o valor atual do item do DynamoDB. Por padrão, ele usa uma leitura fortemente consistente, mas isso pode ser configurado usando o campo consistentRead no bloco condition e compará-lo com o resultado esperado:

  • Para a PutItem operação, a função do AWS AppSync DynamoDB compara o valor atual com o que ela tentou gravar, excluindo quaisquer atributos listados na equalsIgnore comparação. Se os itens forem os mesmos, ele tratará a operação como bem-sucedida e retornará o item recuperado do DynamoDB. Caso contrário, ele seguirá a estratégia configurada.

    Por exemplo, se o objeto da solicitação PutItem se parecer com o seguinte:

    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'] } }; }

    E o item que está atualmente no DynamoDB se parecer com o seguinte:

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

    A função do AWS AppSync DynamoDB compararia o item que tentou gravar com o valor atual, verificaria que a única diferença era o version campo, mas, como está configurada para ignorar o version campo, ela trata a operação como bem-sucedida e retorna o item que foi recuperado do DynamoDB.

  • Para a DeleteItem operação, a função do AWS AppSync DynamoDB verifica se um item foi retornado do DynamoDB. Se nenhum item foi retornado, ele tratará a operação como bem-sucedida. Caso contrário, ele seguirá a estratégia configurada.

  • Para a UpdateItem operação, a função do AWS AppSync DynamoDB não tem informações suficientes para determinar se o item atualmente no DynamoDB corresponde ao resultado esperado e, portanto, segue a estratégia configurada.

Se o estado atual do objeto no DynamoDB for diferente do resultado esperado, a função do AWS AppSync DynamoDB segue a estratégia configurada para rejeitar a mutação ou invocar uma função do Lambda para determinar o que fazer a seguir.

Seguir a estratégia "Rejeitar"

Ao seguir a Reject estratégia, a função do AWS AppSync DynamoDB retorna um erro para a mutação.

Por exemplo, considere a solicitação de mutação a seguir:

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

Se o item retornado do DynamoDB for semelhante ao seguinte:

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

E o manipulador de resposta da função tem a seguinte aparência:

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 }

A resposta do GraphQL é semelhante à seguinte:

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

Além disso, se qualquer campo no objeto retornado for preenchido por outros resolvedores e a mutação foi bem-sucedida, eles não serão resolvidos quando o objeto for retornado na seção error.

Seguir a estratégia "Personalizada"

Ao seguir a Custom estratégia, a função do AWS AppSync DynamoDB invoca uma função do Lambda para decidir o que fazer a seguir. A Função Lambda escolhe um destas opções a seguir:

  • reject a mutação. Isso faz com que a função do AWS AppSync DynamoDB se comporte como se a estratégia configurada fosseReject, retornando um erro para a mutação e o valor atual do objeto no DynamoDB, conforme descrito na seção anterior.

  • discard a mutação. Isso faz com que a função do AWS AppSync DynamoDB ignore silenciosamente a falha na verificação da condição e retorna o valor no DynamoDB.

  • retry a mutação. Isso faz com que a função do AWS AppSync DynamoDB repita a mutação com um novo objeto de solicitação.

A solicitação de invocação do Lambda

A função AWS AppSync DynamoDB invoca a função Lambda especificada no. lambdaArn Ele usa o mesmo service-role-arn configurado na fonte de dados. A carga da invocação tem a seguinte estrutura:

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

Os campos são definidos da seguinte forma:

arguments

Os argumentos da mutação do GraphQL. Isso é o mesmo que os argumentos disponíveis para o objeto da solicitação em context.arguments.

requestMapping

O objeto de solicitação para essa operação.

currentValue

O valor atual do objeto no DynamoDB.

resolver

Informações sobre o AWS AppSync resolvedor ou a função.

identity

Informações sobre o chamador. Isso é o mesmo que as informações de identidade disponíveis para o objeto da solicitação em context.identity.

Um exemplo completo da carga:

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

A resposta de invocação do Lambda

A função Lambda pode inspecionar a carga útil da invocação e aplicar qualquer lógica de negócios para decidir como a função do AWS AppSync DynamoDB deve lidar com a falha. Existem três opções para tratamento da falha de verificação da condição:

  • reject a mutação. A carga da resposta para essa opção deve ter a seguinte estrutura:

    { "action": "reject" }

    Isso faz com que a função do AWS AppSync DynamoDB se comporte como se a estratégia configurada fosseReject, retornando um erro para a mutação e o valor atual do objeto no DynamoDB, conforme descrito na seção acima.

  • discard a mutação. A carga da resposta para essa opção deve ter a seguinte estrutura:

    { "action": "discard" }

    Isso faz com que a função do AWS AppSync DynamoDB ignore silenciosamente a falha na verificação da condição e retorna o valor no DynamoDB.

  • retry a mutação. A carga da resposta para essa opção deve ter a seguinte estrutura:

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

    Isso faz com que a função do AWS AppSync DynamoDB repita a mutação com um novo objeto de solicitação. A estrutura da seção retryMapping depende da operação do DynamoDB e é um subconjunto do objeto da solicitação completo para essa operação.

    Em PutItem, a seção retryMapping tem a seguinte estrutura. Para obter uma descrição do attributeValues campo, consulte PutItem.

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

    Em UpdateItem, a seção retryMapping tem a seguinte estrutura. Para obter uma descrição da update seção, consulte UpdateItem.

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

    Em DeleteItem, a seção retryMapping tem a seguinte estrutura.

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

    Não há como especificar uma operação ou chave diferente na qual trabalhar. A função do AWS AppSync DynamoDB só permite novas tentativas da mesma operação no mesmo objeto. Além disso, a seção condition não permite que um conditionalCheckFailedHandler seja especificado. Se a nova tentativa falhar, a função do AWS AppSync DynamoDB segue a estratégia. Reject

Veja aqui um exemplo de função do Lambda para lidar com uma solicitação PutItem com falha. A lógica de negócios analisa quem fez a chamada. Se foi feita pelo jeffTheAdmin, ela tentará novamente a solicitação, atualizando version e expectedVersion do item atualmente no DynamoDB. Caso contrário, ela rejeitará a mutação.

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