Tutorial: resolvedores do DynamoDB - AWS AppSync

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á.

Tutorial: resolvedores do DynamoDB

nota

Agora, oferecemos suporte principalmente ao runtime do APPSYNC_JS e sua documentação. Considere usar o runtime do APPSYNC_JS e seus guias disponíveis aqui.

Este tutorial mostra como você pode trazer suas próprias tabelas do Amazon DynamoDB para o AWS AppSync e conectá-las a uma API GraphQL.

Você pode permitir que o AWS AppSync provisione recursos do DynamoDB em seu nome. Ou, se preferir, você pode conectar as tabelas existentes a um esquema do GraphQL criando uma fonte de dados e um resolvedor. Em ambos os casos, você poderá ler e gravar no banco de dados do DynamoDB por meio de instruções do GraphQL e assinar dados em tempo real.

Existem etapas de configuração específicas que precisam ser concluídas para que as instruções do GraphQL sejam traduzidas para operações do DynamoDB e para que as respostas sejam traduzidas novamente para o GraphQL. Esse tutorial descreve o processo de configuração por meio de vários cenários reais e padrões de acesso aos dados.

Configuração de tabelas do DynamoDB

Para começar este tutorial, primeiro você precisa seguir as etapas abaixo para provisionar recursos da AWS.

  1. Provisione recursos da AWS usando o seguinte modelo AWS CloudFormation na CLI:

    aws cloudformation create-stack \ --stack-name AWSAppSyncTutorialForAmazonDynamoDB \ --template-url https://s3.us-west-2.amazonaws.com/awsappsync/resources/dynamodb/AmazonDynamoDBCFTemplate.yaml \ --capabilities CAPABILITY_NAMED_IAM

    Como alternativa, você pode iniciar a pilha do AWS CloudFormation a seguir na região US-West 2 (Oregon) em sua conta da AWS.

    Isso cria o seguinte:

    • Uma tabela do DynamoDB chamada AppSyncTutorial-Post que armazenará os dados de Post.

    • Um perfil do IAM e política gerenciada pelo IAM associada para permitir que o AWS AppSync interaja com a tabela de Post.

  2. Para ver mais detalhes sobre a pilha e os recursos criados, execute o seguinte comando da CLI:

    aws cloudformation describe-stacks --stack-name AWSAppSyncTutorialForAmazonDynamoDB
  3. Para excluir os recursos mais tarde, execute o seguinte:

    aws cloudformation delete-stack --stack-name AWSAppSyncTutorialForAmazonDynamoDB

Criação da API GraphQL

Para criar a API GraphQL no AWS AppSync:

  1. Faça login no AWS Management Console e abra o console do AppSync.

    1. No painel de APIs, escolha Criar API.

  2. Na janela Personalizar sua API ou importar a partir do Amazon DynamoDB, escolha Criar a partir do zero.

    1. Escolha Iniciar à direita da mesma janela.

  3. No campo Nome da API, defina o nome da API para AWSAppSyncTutorial.

  4. Escolha Criar.

O console do AWS AppSync cria uma nova API GraphQL para você usando o modo de autenticação da chave da API. Você pode usar o console para configurar o restante da API GraphQL e executar consultas nela durante o restante desse tutorial.

Definição de uma API Post básica

Agora que você configurou uma API GraphQL do AWS AppSync, você pode configurar um esquema básico que permite a criação, recuperação e exclusão básica de dados publicados.

  1. Faça login no AWS Management Console e abra o console do AppSync.

    1. No painel de APIs, escolha a API que você acabou de criar.

  2. Na barra lateral, escolha Esquema.

    1. No painel Esquema, substitua o conteúdo pelo seguinte código:

      schema { query: Query mutation: Mutation } type Query { getPost(id: ID): Post } type Mutation { addPost( id: ID! author: String! title: String! content: String! url: String! ): Post! } type Post { id: ID! author: String title: String content: String url: String ups: Int! downs: Int! version: Int! }
  3. Escolha Salvar.

Esse esquema define um tipo Post e operações para adicionar e obter objetos Post.

Configuração da fonte de dados para as tabelas do DynamoDB

Em seguida, vincule as consultas e mutações definidas no esquema à tabela AppSyncTutorial-Post do DynamoDB.

Primeiro, o AWS AppSync precisa estar ciente das tabelas. Faça isso ao configurar uma fonte de dados no AWS AppSync:

  1. Faça login no AWS Management Console e abra o console do AppSync.

    1. No painel de APIs, escolha sua API GraphQL.

    2. Na barra lateral, escolha Fontes de dados.

  2. Escolha Criar fonte de dados.

    1. Para Nome da fonte de dados, insira em PostDynamoDBTable.

    2. Para o tipo de fonte de dados, escolha Tabela do Amazon DynamoDB.

    3. Para Região, escolha US-WEST-2.

    4. Em Nome da tabela, escolha a tabela AppSyncTutorial-post do DynamoDB.

    5. Crie um perfil do IAM (recomendado) ou escolha uma função existente que tenha permissão do IAM lambda:invokeFunction. Os perfis existentes precisam de uma política de confiança, conforme explicado na seção Anexar uma fonte de dados.

      Veja a seguir um exemplo de política do IAM que tem as permissões necessárias para executar as operações no recurso:

      { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "lambda:invokeFunction" ], "Resource": [ "arn:aws:lambda:us-west-2:123456789012:function:myFunction", "arn:aws:lambda:us-west-2:123456789012:function:myFunction:*" ] } ] }
  3. Escolha Criar.

Configuração do resolvedor addPost (PutItem do DynamoDB)

Assim que o AWS AppSync estiver ciente da tabela do DynamoDB, vincule-a a consultas e mutações individuais definindo Resolvedores. O primeiro resolvedor criado é o resolvedor addPost, que permite criar uma publicação na tabela AppSyncTutorial-Post do DynamoDB.

Um resolvedor tem os seguintes componentes:

  • A local no esquema do GraphQL para anexar o resolvedor. Nesse caso, você está configurando um resolvedor no campo addPost no tipo Mutation. Esse resolvedor será invocado quando o chamador chamar mutation { addPost(...){...} }.

  • A fonte de dados a ser usada para esse resolvedor. Nesse caso, você deseja usar a fonte de dados PostDynamoDBTable definida anteriormente, para que possa adicionar entradas na tabela do DynamoDB AppSyncTutorial-Post.

  • O modelo de mapeamento da solicitação. A finalidade do modelo de mapeamento da solicitação é receber a solicitação de entrada do chamador e traduzi-la em instruções para o AWS AppSync executar mediante o DynamoDB.

  • O modelo de mapeamento da resposta. O trabalho do modelo de mapeamento da resposta é receber a resposta do DynamoDB e traduzi-la de volta para algo esperado pelo GraphQL. Isso é útil se a forma dos dados no DynamoDB for diferente para o tipo Post no GraphQL, mas, nesse caso, elas têm a mesma forma, portanto basta transmitir os dados.

Como configurar o resolvedor:

  1. Faça login no AWS Management Console e abra o Console do AppSync.

    1. No painel de APIs, escolha sua API GraphQL.

    2. Na barra lateral, escolha Fontes de dados.

  2. Escolha Criar fonte de dados.

    1. Para Nome da fonte de dados, insira em PostDynamoDBTable.

    2. Para o tipo de fonte de dados, escolha Tabela do Amazon DynamoDB.

    3. Para Região, escolha US-WEST-2.

    4. Em Nome da tabela, escolha a tabela AppSyncTutorial-post do DynamoDB.

    5. Crie um perfil do IAM (recomendado) ou escolha uma função existente que tenha permissão do IAM lambda:invokeFunction. Os perfis existentes precisam de uma política de confiança, conforme explicado na seção Anexar uma fonte de dados.

      Veja a seguir um exemplo de política do IAM que tem as permissões necessárias para executar as operações no recurso:

      { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "lambda:invokeFunction" ], "Resource": [ "arn:aws:lambda:us-west-2:123456789012:function:myFunction", "arn:aws:lambda:us-west-2:123456789012:function:myFunction:*" ] } ] }
  3. Escolha Criar.

  4. Escolha a guia Esquema.

  5. No painel Tipos de dados à direita, encontre o campo addPost no tipo Mutação e, em seguida, escolha Anexar.

  6. No menu Ação, escolha Atualizar runtime e selecione Resolvedor de unidade (somente VTL).

  7. Em Nome da fonte de dados, escolha PostDynamoDBTable.

  8. Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    { "version" : "2017-02-28", "operation" : "PutItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id) }, "attributeValues" : { "author" : $util.dynamodb.toDynamoDBJson($context.arguments.author), "title" : $util.dynamodb.toDynamoDBJson($context.arguments.title), "content" : $util.dynamodb.toDynamoDBJson($context.arguments.content), "url" : $util.dynamodb.toDynamoDBJson($context.arguments.url), "ups" : { "N" : 1 }, "downs" : { "N" : 0 }, "version" : { "N" : 1 } } }

    Observação: um tipo é especificado em todas as chaves e valores de atributo. Por exemplo, defina o campo author para { "S" : "${context.arguments.author}" }. A parte S indica ao AWS AppSync e ao DynamoDB que o valor será uma string. O valor real é preenchido a partir do argumento author. Da mesma forma, o campo version é um campo de número pois ele usa N para o tipo. Finalmente, você também está inicializando os campos ups, downs e version.

    Neste tutorial, você especificou que o tipo ID! do GraphQL, que indexa o novo item inserido no DynamoDB, vem como parte dos argumentos do cliente. AWS AppSync é fornecido com um utilitário para geração automática de ID chamado $utils.autoId() que você também poderia ter usado na forma de "id" : { "S" : "${$utils.autoId()}" }. Depois, basta deixar o id: ID! fora da definição do esquema de addPost() e ele seria inserido automaticamente. Você não usará essa técnica para esse tutorial, mas deve considerá-la como uma das melhores práticas ao gravar em tabelas do DynamoDB.

    Para obter mais informações sobre os modelos de mapeamento, consulte a documentação de referência Visão geral do modelo de mapeamento do resolvedor. Para obter mais informações sobre o mapeamento da solicitação GetItem, consulte a documentação de referência GetItem. Para obter mais informações sobre os tipos, consulte a documentação de referência Mapeamento da solicitação.

  9. Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    $utils.toJson($context.result)

    Observação: como o formato dos dados na tabela AppSyncTutorial-Post corresponde exatamente ao formato do tipo Post no GraphQL, o modelo de mapeamento da resposta apenas transmite os resultados diretamente. Observe também que todos os exemplos desse tutorial usam o mesmo modelo de mapeamento da resposta, portanto você só cria um arquivo.

  10. Escolha Salvar.

Chamar a API para adicionar uma publicação

Agora que o resolvedor está configurado, o AWS AppSync pode traduzir uma mutação addPost de entrada para uma operação PutItem do DynamoDB. Agora você pode executar uma mutação para colocar algo na tabela.

  • Escolha a guia Consultas.

  • No painel Consultas, cole a seguinte mutação:

    mutation addPost { addPost( id: 123 author: "AUTHORNAME" title: "Our first post!" content: "This is our first post." url: "https://aws.amazon.com/appsync/" ) { id author title content url ups downs version } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • Os resultados da publicação recém-criada devem aparecer no painel de resultados à direita do painel de consulta. A aparência deve ser semelhante à seguinte:

    { "data": { "addPost": { "id": "123", "author": "AUTHORNAME", "title": "Our first post!", "content": "This is our first post.", "url": "https://aws.amazon.com/appsync/", "ups": 1, "downs": 0, "version": 1 } } }

Veja o que aconteceu:

  • O AWS AppSync recebeu uma solicitação de mutação addPost.

  • O AWS AppSync recebeu a solicitação e o modelo de mapeamento da solicitação e gerou um documento de mapeamento da solicitação. Isso teria a seguinte aparência:

    { "version" : "2017-02-28", "operation" : "PutItem", "key" : { "id" : { "S" : "123" } }, "attributeValues" : { "author": { "S" : "AUTHORNAME" }, "title": { "S" : "Our first post!" }, "content": { "S" : "This is our first post." }, "url": { "S" : "https://aws.amazon.com/appsync/" }, "ups" : { "N" : 1 }, "downs" : { "N" : 0 }, "version" : { "N" : 1 } } }
  • O AWS AppSync usou o documento de mapeamento da solicitação para gerar e executar uma solicitação PutItem do DynamoDB.

  • O AWS AppSync recebeu os resultados da solicitação PutItem e os converteu de volta para tipos do GraphQL.

    { "id" : "123", "author": "AUTHORNAME", "title": "Our first post!", "content": "This is our first post.", "url": "https://aws.amazon.com/appsync/", "ups" : 1, "downs" : 0, "version" : 1 }
  • Os transmitiu por meio do documento de mapeamento da resposta, sem alterações.

  • Retornou o objeto recém-criado na resposta do GraphQL.

Configuração do resolvedor getPost (GetItem do DynamoDB)

Agora que você pode adicionar dados à tabela AppSyncTutorial-Post do DynamoDB, é necessário configurar a consulta getPost para que ela possa recuperar esses dados da tabela AppSyncTutorial-Post. Para fazer isso, vamos configurar outro resolvedor.

  • Escolha a guia Esquema.

  • No painel Tipos de dados à direita, encontre o campo getPost no tipo Consulta e, em seguida, escolha Anexar.

  • No menu Ação, escolha Atualizar runtime e selecione Resolvedor de unidade (somente VTL).

  • Em Nome da fonte de dados, escolha PostDynamoDBTable.

  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    { "version" : "2017-02-28", "operation" : "GetItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id) } }
  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    $utils.toJson($context.result)
  • Escolha Salvar.

Chamar a API para obter uma publicação

Agora que o resolvedor foi configurado, o AWS AppSync sabe como converter uma consulta getPost de entrada em uma operação GetItem do DynamoDB. Agora é possível executar uma consulta para recuperar a publicação criada anteriormente.

  • Escolha a guia Consultas.

  • No painel Consultas, cole o seguinte:

    query getPost { getPost(id:123) { id author title content url ups downs version } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • A publicação recuperada do DynamoDB deve aparecer no painel de resultados à direita do painel de consulta. A aparência deve ser semelhante à seguinte:

    { "data": { "getPost": { "id": "123", "author": "AUTHORNAME", "title": "Our first post!", "content": "This is our first post.", "url": "https://aws.amazon.com/appsync/", "ups": 1, "downs": 0, "version": 1 } } }

Veja o que aconteceu:

  • O AWS AppSync recebeu uma solicitação de consulta getPost.

  • O AWS AppSync recebeu a solicitação e o modelo de mapeamento da solicitação e gerou um documento de mapeamento da solicitação. Isso teria a seguinte aparência:

    { "version" : "2017-02-28", "operation" : "GetItem", "key" : { "id" : { "S" : "123" } } }
  • O AWS AppSync usou o documento de mapeamento da solicitação para gerar e executar uma solicitação GetItem do DynamoDB.

  • O AWS AppSync recebeu os resultados da solicitação GetItem e os converteu de volta para tipos do GraphQL.

    { "id" : "123", "author": "AUTHORNAME", "title": "Our first post!", "content": "This is our first post.", "url": "https://aws.amazon.com/appsync/", "ups" : 1, "downs" : 0, "version" : 1 }
  • Os transmitiu por meio do documento de mapeamento da resposta, sem alterações.

  • Retornou o objeto recuperado na resposta.

Como alternativa, utilize o exemplo a seguir:

query getPost { getPost(id:123) { id author title } }

Se sua consulta getPost precisar apenas de id, author e title, você poderá alterar seu modelo de mapeamento da solicitação para usar expressões de projeção para especificar apenas os atributos que deseja da tabela do DynamoDB para evitar transferência desnecessária de dados do DynamoDB para AWS AppSync. Por exemplo, o modelo de mapeamento da solicitação pode se parecer com o trecho abaixo:

{ "version" : "2017-02-28", "operation" : "GetItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id) }, "projection" : { "expression" : "#author, id, title", "expressionNames" : { "#author" : "author"} } }

Criar uma mutação updatePost (UpdateItem do DynamoDB)

Até agora, você pode criar e recuperar objetos Post no DynamoDB. Depois, você configurará uma nova mutação para que possamos atualizar o objeto. Você fará isso usando a operação UpdateItem do DynamoDB.

  • Escolha a guia Esquema.

  • No painel Esquema, modifique o tipo Mutation para adicionar uma nova mutação updatePost da seguinte forma:

    type Mutation { updatePost( id: ID!, author: String!, title: String!, content: String!, url: String! ): Post addPost( author: String! title: String! content: String! url: String! ): Post! }
  • Escolha Salvar.

  • No painel Tipos de dados à direita, encontre o campo updatePost recém-criado no tipo Mutação e, em seguida, escolha Anexar.

  • No menu Ação, escolha Atualizar runtime e selecione Resolvedor de unidade (somente VTL).

  • Em Nome da fonte de dados, escolha PostDynamoDBTable.

  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    { "version" : "2017-02-28", "operation" : "UpdateItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id) }, "update" : { "expression" : "SET author = :author, title = :title, content = :content, #url = :url ADD version :one", "expressionNames": { "#url" : "url" }, "expressionValues": { ":author" : $util.dynamodb.toDynamoDBJson($context.arguments.author), ":title" : $util.dynamodb.toDynamoDBJson($context.arguments.title), ":content" : $util.dynamodb.toDynamoDBJson($context.arguments.content), ":url" : $util.dynamodb.toDynamoDBJson($context.arguments.url), ":one" : { "N": 1 } } } }

    Observação: esse resolvedor está usando a UpdateItem do DynamoDB, que é bem diferente da operação PutItem. Em vez de escrever o item inteiro, você está apenas pedindo ao DynamoDB para atualizar determinados atributos. Isso é feito usando expressões de atualização do DynamoDB. A expressão em si é especificada no campo expression na seção update. Ela diz para definir o author, o title, o content e os atributos de url e, em seguida, incrementar o campo version. Os valores a serem usados não aparecem na expressão em si; a expressão tem espaços reservados com nomes que começam com "dois pontos", que são definidos no campo expressionValues. Finalmente, o DynamoDB tem palavras reservadas que não podem aparecer no expression. Por exemplo, url é uma palavra reservada, então, para atualizar o campo url é possível usar espaços reservados de nome e defini-los no campo expressionNames.

    Para obter mais informações sobre o mapeamento da solicitação UpdateItem, consulte a documentação de referência UpdateItem. Para obter mais informações sobre como gravar expressões de atualização, consulte a documentação UpdateExpressions do DynamoDB.

  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    $utils.toJson($context.result)

Chamar a API para atualizar uma publicação

Agora que o resolvedor foi configurado, o AWS AppSync sabe como traduzir uma mutação update de entrada para uma operação Update do DynamoDB. Agora você pode executar uma mutação para atualizar o item escrito anteriormente.

  • Escolha a guia Consultas.

  • No painel Consultas, cole a seguinte mutação. Também será necessário atualizar o argumento id para o valor anotado anteriormente.

    mutation updatePost { updatePost( id:"123" author: "A new author" title: "An updated author!" content: "Now with updated content!" url: "https://aws.amazon.com/appsync/" ) { id author title content url ups downs version } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • A publicação atualizada no DynamoDB deve aparecer no painel de resultados à direita do painel de consulta. A aparência deve ser semelhante à seguinte:

    { "data": { "updatePost": { "id": "123", "author": "A new author", "title": "An updated author!", "content": "Now with updated content!", "url": "https://aws.amazon.com/appsync/", "ups": 1, "downs": 0, "version": 2 } } }

Neste exemplo, os campos ups e downs não foram modificados pois o modelo de mapeamento da solicitação não solicitou que o AWS AppSync e o DynamoDB fizessem algo com esses campos. Além disso, o campo version foi incrementado em 1 pois você solicitou que o AWS AppSync e o DynamoDB adicionassem 1 ao campo version.

Modificação do resolvedor updatePost (UpdateItem do DynamoDB)

Esse é um bom início para a mutação updatePost, mas tem dois problemas principais:

  • Se quiser atualizar apenas um único campo, é necessário atualizar todos os campos.

  • Se duas pessoas estiverem modificando o objeto, possivelmente haverá perda de informações.

Para resolver esses problemas, você modificará a mutação updatePost para modificar apenas os argumentos que foram especificados na solicitação e, depois, adicionará uma condição à operação UpdateItem.

  1. Escolha a guia Esquema.

  2. No painel Esquema, modifique o campo updatePost no tipo Mutation e remova os pontos de exclamação dos argumentos author, title, content e url, mantendo o campo id como está. Isso os tornará argumento opcional. Além disso, adicione um novo argumento expectedVersion obrigatório.

    type Mutation { updatePost( id: ID!, author: String, title: String, content: String, url: String, expectedVersion: Int! ): Post addPost( author: String! title: String! content: String! url: String! ): Post! }
  3. Escolha Salvar.

  4. No painel Tipos de dados, encontre o campo updatePost no tipo Mutação.

  5. Escolha PostDynamoDBTable para abrir o resolvedor existente.

  6. Em Configurar o modelo de mapeamento da solicitação, modifique o modelo de mapeamento da solicitação da seguinte forma:

    { "version" : "2017-02-28", "operation" : "UpdateItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id) }, ## Set up some space to keep track of things you're updating ** #set( $expNames = {} ) #set( $expValues = {} ) #set( $expSet = {} ) #set( $expAdd = {} ) #set( $expRemove = [] ) ## Increment "version" by 1 ** $!{expAdd.put("version", ":one")} $!{expValues.put(":one", { "N" : 1 })} ## Iterate through each argument, skipping "id" and "expectedVersion" ** #foreach( $entry in $context.arguments.entrySet() ) #if( $entry.key != "id" && $entry.key != "expectedVersion" ) #if( (!$entry.value) && ("$!{entry.value}" == "") ) ## If the argument is set to "null", then remove that attribute from the item in DynamoDB ** #set( $discard = ${expRemove.add("#${entry.key}")} ) $!{expNames.put("#${entry.key}", "$entry.key")} #else ## Otherwise set (or update) the attribute on the item in DynamoDB ** $!{expSet.put("#${entry.key}", ":${entry.key}")} $!{expNames.put("#${entry.key}", "$entry.key")} $!{expValues.put(":${entry.key}", { "S" : "${entry.value}" })} #end #end #end ## Start building the update expression, starting with attributes you're going to SET ** #set( $expression = "" ) #if( !${expSet.isEmpty()} ) #set( $expression = "SET" ) #foreach( $entry in $expSet.entrySet() ) #set( $expression = "${expression} ${entry.key} = ${entry.value}" ) #if ( $foreach.hasNext ) #set( $expression = "${expression}," ) #end #end #end ## Continue building the update expression, adding attributes you're going to ADD ** #if( !${expAdd.isEmpty()} ) #set( $expression = "${expression} ADD" ) #foreach( $entry in $expAdd.entrySet() ) #set( $expression = "${expression} ${entry.key} ${entry.value}" ) #if ( $foreach.hasNext ) #set( $expression = "${expression}," ) #end #end #end ## Continue building the update expression, adding attributes you're going to REMOVE ** #if( !${expRemove.isEmpty()} ) #set( $expression = "${expression} REMOVE" ) #foreach( $entry in $expRemove ) #set( $expression = "${expression} ${entry}" ) #if ( $foreach.hasNext ) #set( $expression = "${expression}," ) #end #end #end ## Finally, write the update expression into the document, along with any expressionNames and expressionValues ** "update" : { "expression" : "${expression}" #if( !${expNames.isEmpty()} ) ,"expressionNames" : $utils.toJson($expNames) #end #if( !${expValues.isEmpty()} ) ,"expressionValues" : $utils.toJson($expValues) #end }, "condition" : { "expression" : "version = :expectedVersion", "expressionValues" : { ":expectedVersion" : $util.dynamodb.toDynamoDBJson($context.arguments.expectedVersion) } } }
  7. Escolha Salvar.

Este modelo é um dos exemplos mais complexos. Ele demonstra a potência e a flexibilidade dos modelos de mapeamento. Ele percorre todos os argumentos, ignorando id e expectedVersion. Se o argumento estiver definido como algo, ele solicitará que o AWS AppSync e o DynamoDB atualizem esse atributo no objeto no DynamoDB. Se o atributo estiver definido como nulo, ele solicitará que o AWS AppSync e o DynamoDB removam esse atributo do objeto da publicação. Se um argumento não foi especificado, nada será feito com o atributo. Ele também incrementa o campo version.

Além disso, há uma nova seção condition. Uma expressão de condição permite que você informe o AWS AppSync e o DynamoDB se a solicitação deve ou não ser bem-sucedida com base no estado do objeto que já está no DynamoDB antes que a operação seja realizada. Nesse caso, você deseja que a solicitação UpdateItem seja bem-sucedida apenas se o campo version do item atualmente no DynamoDB corresponder ao argumento expectedVersion.

Para obter mais informações sobre as expressões de condições, consulte a documentação de referência Expressões de condições.

Chamar a API para atualizar uma publicação

Vamos tentar atualizar o objeto Post com o novo resolvedor:

  • Escolha a guia Consultas.

  • No painel Consultas, cole a mutação a seguir. Também será necessário atualizar o argumento id para o valor anotado anteriormente.

    mutation updatePost { updatePost( id:123 title: "An empty story" content: null expectedVersion: 2 ) { id author title content url ups downs version } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • A publicação atualizada no DynamoDB deve aparecer no painel de resultados à direita do painel de consulta. A aparência deve ser semelhante à seguinte:

    { "data": { "updatePost": { "id": "123", "author": "A new author", "title": "An empty story", "content": null, "url": "https://aws.amazon.com/appsync/", "ups": 1, "downs": 0, "version": 3 } } }

Nessa solicitação, foi solicitado que o AWS AppSync e o DynamoDB atualizassem somente os campos title e content. Ele ignorou todos os outros campos (além de incrementar o campo version). Definiu-se o atributo title para um novo valor e o atributo content foi removido da publicação. Os campos author, url, ups e downs foram mantidos.

Tente executar a solicitação de mutação novamente, deixando a solicitação exatamente como está. Você verá uma resposta semelhante à seguinte:

{ "data": { "updatePost": null }, "errors": [ { "path": [ "updatePost" ], "data": { "id": "123", "author": "A new author", "title": "An empty story", "content": null, "url": "https://aws.amazon.com/appsync/", "ups": 1, "downs": 0, "version": 3 }, "errorType": "DynamoDB:ConditionalCheckFailedException", "locations": [ { "line": 2, "column": 3 } ], "message": "The conditional request failed (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ConditionalCheckFailedException; Request ID: ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ)" } ] }

A solicitação falha pois a expressão de condição é avaliada como falsa:

  • Na primeira vez que você executou a solicitação, o valor do campo version da publicação no DynamoDB era 2, que correspondia ao argumento expectedVersion. A solicitação foi bem-sucedida, o que significa que o campo version foi incrementado no DynamoDB para 3.

  • Na segunda vez que a solicitação foi executada, o valor do campo version da publicação no DynamoDB era 3, que não correspondeu ao argumento expectedVersion.

Esse padrão é geralmente chamado de bloqueio positivo.

Um atributo do resolvedor do DynamoDB do AWS AppSync é que ele retorna o valor atual do objeto da publicação no DynamoDB. Encontre isso no campo data na seção errors da resposta do GraphQL. O aplicativo pode usar essas informações para decidir como deve continuar. Nesse caso, é possível ver que o campo version do objeto no DynamoDB está definido como 3; portanto, podemos apenas atualizar o argumento expectedVersion para 3 e a solicitação teria êxito novamente.

Para obter mais informações sobre o tratamento de falhas da verificação de condição, consulte a documentação de referência do modelo de mapeamento Expressões de condições.

Criar mutações upvotePost e downvotePost (UpdateItem do DynamoDB)

O tipo Post tem campos ups e downs para habilitar o registro de votos positivos e negativos, mas até agora a API não permite fazer nada com eles. Vamos adicionar algumas mutações para permitir votos positivos e negativos nas publicações.

  • Escolha a guia Esquema.

  • No painel Esquema, modifique o tipo Mutation para adicionar novas mutações upvotePost e downvotePost da seguinte forma:

    type Mutation { upvotePost(id: ID!): Post downvotePost(id: ID!): Post updatePost( id: ID!, author: String, title: String, content: String, url: String, expectedVersion: Int! ): Post addPost( author: String!, title: String!, content: String!, url: String! ): Post! }
  • Escolha Salvar.

  • No painel Tipos de dados à direita, encontre o campo upvotePost recém-criado no tipo Mutação e, em seguida, escolha Anexar.

  • No menu Ação, escolha Atualizar runtime e selecione Resolvedor de unidade (somente VTL).

  • Em Nome da fonte de dados, escolha PostDynamoDBTable.

  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    { "version" : "2017-02-28", "operation" : "UpdateItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id) }, "update" : { "expression" : "ADD ups :plusOne, version :plusOne", "expressionValues" : { ":plusOne" : { "N" : 1 } } } }
  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    $utils.toJson($context.result)
  • Escolha Salvar.

  • No painel Tipos de dados à direita, encontre o campo downvotePost recém-criado no tipo Mutação e, em seguida, escolha Anexar.

  • Em Nome da fonte de dados, escolha PostDynamoDBTable.

  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    { "version" : "2017-02-28", "operation" : "UpdateItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id) }, "update" : { "expression" : "ADD downs :plusOne, version :plusOne", "expressionValues" : { ":plusOne" : { "N" : 1 } } } }
  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    $utils.toJson($context.result)
  • Escolha Salvar.

Chamar a API para realizar voto positivo ou negativo em uma Publicação

Agora que os novos resolvedores foram configurados, o AWS AppSync sabe como traduzir uma mutação upvotePost ou downvote de entrada para uma operação UpdateItem do DynamoDB. Agora é possível executar mutações para realizar votos positivos ou negativos na publicação criada anteriormente.

  • Escolha a guia Consultas.

  • No painel Consultas, cole a mutação a seguir. Também será necessário atualizar o argumento id para o valor anotado anteriormente.

    mutation votePost { upvotePost(id:123) { id author title content url ups downs version } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • A publicação é atualizada no DynamoDB e deve aparecer no painel de resultados à direita do painel de consulta. A aparência deve ser semelhante à seguinte:

    { "data": { "upvotePost": { "id": "123", "author": "A new author", "title": "An empty story", "content": null, "url": "https://aws.amazon.com/appsync/", "ups": 6, "downs": 0, "version": 4 } } }
  • Escolha Executar consulta mais algumas vezes. Você deve ver os campos ups e version incrementar em 1 a cada vez que você executar a consulta.

  • Altere a consulta para chamar a mutação downvotePost da seguinte forma:

    mutation votePost { downvotePost(id:123) { id author title content url ups downs version } }
  • Escolha Executar consulta (o botão de reprodução laranja). Dessa vez, você deve ver os campos downs e version incrementar em 1 a cada vez que você executar a consulta.

    { "data": { "downvotePost": { "id": "123", "author": "A new author", "title": "An empty story", "content": null, "url": "https://aws.amazon.com/appsync/", "ups": 6, "downs": 4, "version": 12 } } }

Configuração de um resolvedor deletePost (DeleteItem do DynamoDB)

A próxima mutação que você quer configurar é para excluir uma publicação. Você fará isso usando a operação DeleteItem do DynamoDB.

  • Escolha a guia Esquema.

  • No painel Esquema, modifique o tipo Mutation para adicionar uma nova mutação deletePost da seguinte forma:

    type Mutation { deletePost(id: ID!, expectedVersion: Int): Post upvotePost(id: ID!): Post downvotePost(id: ID!): Post updatePost( id: ID!, author: String, title: String, content: String, url: String, expectedVersion: Int! ): Post addPost( author: String!, title: String!, content: String!, url: String! ): Post! }

    Dessa vez o campo expectedVersion é opcional, o que é explicado mais tarde ao adicionar o modelo de mapeamento da solicitação.

  • Escolha Salvar.

  • No painel Tipos de dados à direita, encontre o campo delete recém-criado no tipo Mutação e, em seguida, escolha Anexar.

  • No menu Ação, escolha Atualizar runtime e selecione Resolvedor de unidade (somente VTL).

  • Em Nome da fonte de dados, escolha PostDynamoDBTable.

  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    { "version" : "2017-02-28", "operation" : "DeleteItem", "key": { "id": $util.dynamodb.toDynamoDBJson($context.arguments.id) } #if( $context.arguments.containsKey("expectedVersion") ) ,"condition" : { "expression" : "attribute_not_exists(id) OR version = :expectedVersion", "expressionValues" : { ":expectedVersion" : $util.dynamodb.toDynamoDBJson($context.arguments.expectedVersion) } } #end }

    Observação: o argumento expectedVersion é opcional. Se o chamador definir um argumento expectedVersion na solicitação, o modelo adiciona uma condição que permite que a solicitação DeleteItem seja bem-sucedida somente se o item já estiver excluído ou se o atributo version da publicação no DynamoDB corresponder exatamente ao expectedVersion. Se omitido, nenhuma expressão de condição será especificada na solicitação DeleteItem. Ele será bem-sucedida independentemente do valor de version, ou se o item existe ou não no DynamoDB.

  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    $utils.toJson($context.result)

    Observação: mesmo que você esteja excluindo um item, é possível retornar o item que foi excluído, caso ainda não tenha sido excluído.

  • Escolha Salvar.

Para obter mais informações sobre o mapeamento da solicitação DeleteItem, consulte a documentação de referência DeleteItem.

Chamar a API para excluir uma publicação

Agora que o resolvedor foi configurado, o AWS AppSync sabe como traduzir uma mutação delete de entrada para uma operação DeleteItem do DynamoDB. Agora você pode executar uma mutação para excluir algo na tabela.

  • Escolha a guia Consultas.

  • No painel Consultas, cole a mutação a seguir. Também será necessário atualizar o argumento id para o valor anotado anteriormente.

    mutation deletePost { deletePost(id:123) { id author title content url ups downs version } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • A publicação é excluída do DynamoDB. Observe que o AWS AppSync retorna o valor do item que foi excluído do DynamoDB, que deve aparecer no painel de resultados à direita do painel de consulta. A aparência deve ser semelhante à seguinte:

    { "data": { "deletePost": { "id": "123", "author": "A new author", "title": "An empty story", "content": null, "url": "https://aws.amazon.com/appsync/", "ups": 6, "downs": 4, "version": 12 } } }

O valor é retornado somente se essa chamada para deletePost foi aquela que realmente a excluiu do DynamoDB.

  • Escolha Executar consulta novamente.

  • A chamada ainda será bem-sucedida, mas nenhum valor é retornado.

    { "data": { "deletePost": null } }

Agora vamos tentar excluir uma publicação, mas dessa vez especificando um expectedValue. No entanto, primeiro é necessário criar uma nova publicação, pois você acabou de excluir aquela com a qual estava trabalhando.

  • No painel Consultas, cole a seguinte mutação:

    mutation addPost { addPost( id:123 author: "AUTHORNAME" title: "Our second post!" content: "A new post." url: "https://aws.amazon.com/appsync/" ) { id author title content url ups downs version } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • Os resultados da publicação recém-criada devem aparecer no painel de resultados à direita do painel de consulta. Anote o id do objeto recém-criado, pois será necessário em alguns instantes. A aparência deve ser semelhante à seguinte:

    { "data": { "addPost": { "id": "123", "author": "AUTHORNAME", "title": "Our second post!", "content": "A new post.", "url": "https://aws.amazon.com/appsync/", "ups": 1, "downs": 0, "version": 1 } } }

Agora vamos tentar excluir a publicação, mas coloque o valor errado para expectedVersion:

  • No painel Consultas, cole a mutação a seguir. Também será necessário atualizar o argumento id para o valor anotado anteriormente.

    mutation deletePost { deletePost( id:123 expectedVersion: 9999 ) { id author title content url ups downs version } }
  • Escolha Executar consulta (o botão de reprodução laranja).

    { "data": { "deletePost": null }, "errors": [ { "path": [ "deletePost" ], "data": { "id": "123", "author": "AUTHORNAME", "title": "Our second post!", "content": "A new post.", "url": "https://aws.amazon.com/appsync/", "ups": 1, "downs": 0, "version": 1 }, "errorType": "DynamoDB:ConditionalCheckFailedException", "locations": [ { "line": 2, "column": 3 } ], "message": "The conditional request failed (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ConditionalCheckFailedException; Request ID: ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ)" } ] }

    A solicitação falhou porque a expressão de condição é avaliada como falsa: o valor para version da publicação no DynamoDB não corresponde ao expectedValue especificado nos argumentos. O valor atual do objeto é retornada no campo data na seção errors da resposta do GraphQL.

  • Repita a solicitação, mas corrija o expectedVersion:

    mutation deletePost { deletePost( id:123 expectedVersion: 1 ) { id author title content url ups downs version } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • Dessa vez, a solicitação é bem-sucedida e o valor que foi excluído do DynamoDB é retornado:

    { "data": { "deletePost": { "id": "123", "author": "AUTHORNAME", "title": "Our second post!", "content": "A new post.", "url": "https://aws.amazon.com/appsync/", "ups": 1, "downs": 0, "version": 1 } } }
  • Escolha Executar consulta novamente.

  • A chamada ainda é bem-sucedida, mas dessa vez nenhum valor é retornado porque a publicação já estava excluída no DynamoDB.

{ "data": { "deletePost": null } }

Configurar o resolvedor allPost (Scan do DynamoDB)

Até agora, a API só será útil se você souber o id de cada publicação a ser examinada. Vamos adicionar um novo resolvedor que retornará todas as publicações na tabela.

  • Escolha a guia Esquema.

  • No painel Esquema, modifique o tipo Query para adicionar uma nova consulta allPost da seguinte forma:

    type Query { allPost(count: Int, nextToken: String): PaginatedPosts! getPost(id: ID): Post }
  • Adicione um novo tipo PaginationPosts:

    type PaginatedPosts { posts: [Post!]! nextToken: String }
  • Escolha Salvar.

  • No painel Tipos de dados à direita, encontre o campo allPost recém-criado no tipo Consulta e, em seguida, escolha Anexar.

  • No menu Ação, escolha Atualizar runtime e selecione Resolvedor de unidade (somente VTL).

  • Em Nome da fonte de dados, escolha PostDynamoDBTable.

  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    { "version" : "2017-02-28", "operation" : "Scan" #if( ${context.arguments.count} ) ,"limit": $util.toJson($context.arguments.count) #end #if( ${context.arguments.nextToken} ) ,"nextToken": $util.toJson($context.arguments.nextToken) #end }

    Esse resolvedor tem dois argumentos opcionais: count, que especifica o número máximo de itens que serão retornados em uma única chamada, e nextToken, que pode ser usado para recuperar o próximo conjunto de resultados, (você mostrará de onde vem o valor para nextToken posteriormente).

  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    { "posts": $utils.toJson($context.result.items) #if( ${context.result.nextToken} ) ,"nextToken": $util.toJson($context.result.nextToken) #end }

    Observação: esse modelo de mapeamento da resposta é diferente de todos os outros até agora. O resultado da consulta allPost é um PaginatedPosts, que contém uma lista de publicações e um token de paginação. A forma desse objeto é diferente para do que é retornado pelo resolvedor do DynamoDB do AWS AppSync: a lista de publicações se chama items nos resultados do resolvedor do DynamoDB do AWS AppSync, mas se chama posts em PaginatedPosts.

  • Escolha Salvar.

Para obter mais informações sobre o mapeamento da solicitação Scan, consulte a documentação de referência Scan.

Chamar a API para verificar todas as publicações

Agora que o resolvedor foi configurado, o AWS AppSync sabe como converter uma consulta allPost de entrada em uma operação Scan do DynamoDB. Agora você pode verificar a tabela para recuperar todas as publicações.

No entanto, antes de testar, é necessário preencher a tabela com alguns dados, pois tudo que foi usado até agora já foi excluído.

  • Escolha a guia Consultas.

  • No painel Consultas, cole a seguinte mutação:

    mutation addPost { post1: addPost(id:1 author: "AUTHORNAME" title: "A series of posts, Volume 1" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } post2: addPost(id:2 author: "AUTHORNAME" title: "A series of posts, Volume 2" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } post3: addPost(id:3 author: "AUTHORNAME" title: "A series of posts, Volume 3" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } post4: addPost(id:4 author: "AUTHORNAME" title: "A series of posts, Volume 4" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } post5: addPost(id:5 author: "AUTHORNAME" title: "A series of posts, Volume 5" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } post6: addPost(id:6 author: "AUTHORNAME" title: "A series of posts, Volume 6" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } post7: addPost(id:7 author: "AUTHORNAME" title: "A series of posts, Volume 7" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } post8: addPost(id:8 author: "AUTHORNAME" title: "A series of posts, Volume 8" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } post9: addPost(id:9 author: "AUTHORNAME" title: "A series of posts, Volume 9" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title } }
  • Escolha Executar consulta (o botão de reprodução laranja).

Agora vamos examinar a tabela, retornando cinco resultados por vez.

  • No painel Consultas, cole a seguinte consulta:

    query allPost { allPost(count: 5) { posts { id title } nextToken } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • As primeiras cinco publicações devem aparecer no painel de resultados à direita do painel de consulta. A aparência deve ser semelhante à seguinte:

    { "data": { "allPost": { "posts": [ { "id": "5", "title": "A series of posts, Volume 5" }, { "id": "1", "title": "A series of posts, Volume 1" }, { "id": "6", "title": "A series of posts, Volume 6" }, { "id": "9", "title": "A series of posts, Volume 9" }, { "id": "7", "title": "A series of posts, Volume 7" } ], "nextToken": "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnRkJEdXdUK09hcnovRGhNTGxLTGdMUEFBQUI1akNDQWVJR0NTcUdTSWIzRFFFSEJxQ0NBZE13Z2dIUEFnRUFNSUlCeUFZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF6ajFodkhKU1paT1pncTRaUUNBUkNBZ2dHWnJiR1dQWGxkMDB1N0xEdGY4Z2JsbktzRjRua1VCcks3TFJLcjZBTFRMeGFwVGJZMDRqOTdKVFQyYVRwSzdzbVdtNlhWWFVCTnFIOThZTzBWZHVkdDI2RlkxMHRqMDJ2QTlyNWJTUWpTbWh6NE5UclhUMG9KZWJSQ2JJbXBlaDRSVlg0Tis0WTVCN1IwNmJQWWQzOVhsbTlUTjBkZkFYMVErVCthaXZoNE5jMk50RitxVmU3SlJ5WmpzMEFkSGduM3FWd2VrOW5oeFVVd3JlK1loUks5QkRzemdiMDlmZmFPVXpzaFZ4cVJRbC93RURlOTcrRmVJdXZNby9NZ1F6dUdNbFRyalpNR3FuYzZBRnhwa0VlZTFtR0FwVDFISElUZlluakptYklmMGUzUmcxbVlnVHVSbDh4S0trNmR0QVoraEhLVDhuNUI3VnF4bHRtSnlNUXBrZGl6KzkyL3VzNDl4OWhrMnVxSW01ZFFwMjRLNnF0dm9ZK1BpdERuQTc5djhzb0grVytYT3VuQ2NVVDY4TVZ1Wk5KYkRuSEFSSEVlaTlVNVBTelU5RGZ6d2pPdmhqWDNJMWhwdWUrWi83MDVHVjlPQUxSTGlwZWZPeTFOZFhwZTdHRDZnQW00bUJUK2c1eC9Ec3ZDbWVnSDFDVXRTdHVuU1ZFa2JpZytQRC9oMUwyRTNqSHhVQldaa28yU256WUc0cG0vV1RSWkFVZHZuQT09In0=" } } }

Você tem cinco resultados e um nextToken que pode ser usado para obter o próximo conjunto de resultados.

  • Atualize a consulta allPost para incluir o nextToken do conjunto de resultados anterior:

    query allPost { allPost( count: 5 nextToken: "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnRlluNktJRWl6V0ZlR3hJOVJkaStrZUFBQUI1akNDQWVJR0NTcUdTSWIzRFFFSEJxQ0NBZE13Z2dIUEFnRUFNSUlCeUFZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF5cW8yUGFSZThnalFpemRCTUNBUkNBZ2dHWk1JODhUNzhIOFVUZGtpdFM2ZFluSWRyVDg4c2lkN1RjZzB2d1k3VGJTTWpSQ2U3WjY3TkUvU2I1dWNETUdDMmdmMHErSGJSL0pteGRzYzVEYnE1K3BmWEtBdU5jSENJdWNIUkJ0UHBPWVdWdCtsS2U5L1pNcWdocXhrem1RaXI1YnIvQkt6dU5hZmJCdE93NmtoM2Jna1BKM0RjWWhpMFBGbmhMVGg4TUVGSjBCcXg3RTlHR1V5N0tUS0JLZlV3RjFQZ0JRREdrNzFYQnFMK2R1S2IrVGtZZzVYMjFrc3NyQmFVTmNXZmhTeXE0ZUJHSWhqZWQ5c3VKWjBSSTc2ZnVQdlZkR3FLNENjQmxHYXhpekZnK2pKK1FneEU1SXduRTNYYU5TR0I4QUpmamR2bU1wbUk1SEdvWjlMUUswclczbG14RDRtMlBsaTNLaEVlcm9pem5zcmdINFpvcXIrN2ltRDN3QkJNd3BLbGQzNjV5Nnc4ZnMrK2FnbTFVOUlKOFFrOGd2bEgySHFROHZrZXBrMWlLdWRIQ25LaS9USnBlMk9JeEVPazVnRFlzRTRUU09HUlVJTkxYY2MvdW1WVEpBMUthV2hWTlAvdjNlSnlZQUszbWV6N2h5WHVXZ1BkTVBNWERQdTdjVnVRa3EwK3NhbGZOd2wvSUx4bHNyNDVwTEhuVFpyRWZvVlV1bXZ5S2VKY1RUU1lET05hM1NwWEd2UT09In0=" ) { posts { id author } nextToken } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • As quatro publicações restantes devem aparecer no painel de resultados à direita do painel de consulta. Não há nextToken nesse conjunto de resultados pois todos os nove resultados foram encontrados, sem nenhum restante. A aparência deve ser semelhante à seguinte:

    { "data": { "allPost": { "posts": [ { "id": "2", "title": "A series of posts, Volume 2" }, { "id": "3", "title": "A series of posts, Volume 3" }, { "id": "4", "title": "A series of posts, Volume 4" }, { "id": "8", "title": "A series of posts, Volume 8" } ], "nextToken": null } } }

Configuração do resolvedor allPostsByAuthor (consulta do DynamoDB)

Além de verificar todas as publicações do DynamoDB, também é possível consultar o DynamoDB para recuperar as publicações criadas por um determinado autor. A tabela do DynamoDB criada anteriormente já possui um GlobalSecondaryIndex chamado author-index que podemos usar com uma operação Query do DynamoDB para recuperar todos as publicações criadas por um determinado autor.

  • Escolha a guia Esquema.

  • No painel Esquema, modifique o tipo Query para adicionar uma nova consulta allPostsByAuthor da seguinte forma:

    type Query { allPostsByAuthor(author: String!, count: Int, nextToken: String): PaginatedPosts! allPost(count: Int, nextToken: String): PaginatedPosts! getPost(id: ID): Post }

    Observação: isso usa o mesmo tipo PaginatedPosts usado com a consulta allPost.

  • Escolha Salvar.

  • No painel Tipos de dados à direita, encontre o campo allPostsByAuthor recém-criado no tipo Consulta e, em seguida, escolha Anexar.

  • No menu Ação, escolha Atualizar runtime e selecione Resolvedor de unidade (somente VTL).

  • Em Nome da fonte de dados, escolha PostDynamoDBTable.

  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    { "version" : "2017-02-28", "operation" : "Query", "index" : "author-index", "query" : { "expression": "author = :author", "expressionValues" : { ":author" : $util.dynamodb.toDynamoDBJson($context.arguments.author) } } #if( ${context.arguments.count} ) ,"limit": $util.toJson($context.arguments.count) #end #if( ${context.arguments.nextToken} ) ,"nextToken": "${context.arguments.nextToken}" #end }

    Como o resolvedor allPost, esse resolvedor tem dois argumentos opcionais: count, que especifica o número máximo de itens que serão retornados em uma única chamada e nextToken, que pode ser usado para recuperar o próximo conjunto de resultados (o valor para nextToken pode ser obtido de uma chamada anterior).

  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    { "posts": $utils.toJson($context.result.items) #if( ${context.result.nextToken} ) ,"nextToken": $util.toJson($context.result.nextToken) #end }

    Observação: esse é o mesmo modelo de mapeamento da resposta usado no resolvedor allPost.

  • Escolha Salvar.

Para obter mais informações sobre o mapeamento da solicitação Query, consulte a documentação de referência Consulta.

Chamar a API para consultar todas as publicações de um autor

Agora que o resolvedor foi configurado, AWS AppSync sabe como traduzir uma mutação allPostsByAuthor recebida em uma operação Query do DynamoDB no índice author-index. Agora você pode consultar a tabela para recuperar todas as publicações de um determinado autor.

Antes de fazer isso, no entanto, vamos preencher a tabela com mais algumas publicações pois até agora todas têm o mesmo autor.

  • Escolha a guia Consultas.

  • No painel Consultas, cole a seguinte mutação:

    mutation addPost { post1: addPost(id:10 author: "Nadia" title: "The cutest dog in the world" content: "So cute. So very, very cute." url: "https://aws.amazon.com/appsync/" ) { author, title } post2: addPost(id:11 author: "Nadia" title: "Did you know...?" content: "AppSync works offline?" url: "https://aws.amazon.com/appsync/" ) { author, title } post3: addPost(id:12 author: "Steve" title: "I like GraphQL" content: "It's great" url: "https://aws.amazon.com/appsync/" ) { author, title } }
  • Escolha Executar consulta (o botão de reprodução laranja).

Agora, vamos consultar a tabela, retornando todas as publicações de autoria da Nadia.

  • No painel Consultas, cole a seguinte consulta:

    query allPostsByAuthor { allPostsByAuthor(author: "Nadia") { posts { id title } nextToken } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • Todas as publicações de autoria da Nadia devem aparecer no painel de resultados à direita do painel de consulta. A aparência deve ser semelhante à seguinte:

    { "data": { "allPostsByAuthor": { "posts": [ { "id": "10", "title": "The cutest dog in the world" }, { "id": "11", "title": "Did you know...?" } ], "nextToken": null } } }

A paginação funciona para Query da mesma forma que funciona para Scan. Por exemplo, vamos procurar todas as publicações por AUTHORNAME, obtendo cinco por vez.

  • No painel Consultas, cole a seguinte consulta:

    query allPostsByAuthor { allPostsByAuthor( author: "AUTHORNAME" count: 5 ) { posts { id title } nextToken } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • Todas as publicações de autoria da AUTHORNAME devem aparecer no painel de resultados à direita do painel de consulta. A aparência deve ser semelhante à seguinte:

    { "data": { "allPostsByAuthor": { "posts": [ { "id": "6", "title": "A series of posts, Volume 6" }, { "id": "4", "title": "A series of posts, Volume 4" }, { "id": "2", "title": "A series of posts, Volume 2" }, { "id": "7", "title": "A series of posts, Volume 7" }, { "id": "1", "title": "A series of posts, Volume 1" } ], "nextToken": "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnSExqRnVhVUR3ZUhEZ2QzNGJ2QlFuY0FBQUNqekNDQW9zR0NTcUdTSWIzRFFFSEJxQ0NBbnd3Z2dKNEFnRUFNSUlDY1FZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF5Qkg4Yk1obW9LVEFTZHM3SUNBUkNBZ2dKQ3dISzZKNlJuN3pyYUVKY1pWNWxhSkNtZW1KZ0F5N1dhZkc2UEdTNHpNQzJycTkwZHFJTFV6Z25wck9Gd3pMS3VOQ2JvUXc3VDI5eCtnVExIbGg4S3BqbzB1YjZHQ3FwcDhvNDVmMG9JbDlmdS9JdjNXcFNNSXFKTXZ1MEVGVWs1VzJQaW5jZGlUaVRtZFdYWlU1bkV2NkgyRFBRQWZYYlNnSmlHSHFLbmJZTUZZM0FTdmRIL0hQaVZBb1RCMk1YZkg0eGJOVTdEbjZtRFNhb2QwbzdHZHJEWDNtODQ1UXBQUVNyUFhHemY0WDkyajhIdlBCSWE4Smcrb0RxbHozUVQ5N2FXUXdYWWU2S0h4emI1ejRITXdEdXEyRDRkYzhoMi9CbW10MzRMelVGUVIyaExSZGRaZ0xkdzF5cHJZdFZwY3dEc1d4UURBTzdOcjV2ZEp4VVR2TVhmODBRSnp1REhXREpTVlJLdDJwWmlpaXhXeGRwRmNod1BzQ3d2aVBqMGwrcWFFWU1jMXNQbENkVkFGem43VXJrSThWbS8wWHlwR2xZb3BSL2FkV0xVekgrbGMrYno1ZEM2SnVLVXdtY1EyRXlZeDZiS0Izbi9YdUViWGdFeU5PMWZTdE1rRlhyWmpvMVpzdlYyUFRjMzMrdEs0ZDhkNkZrdjh5VVR6WHhJRkxIaVNsOUx6VVdtT3BCaWhrTFBCT09jcXkyOHh1UmkzOEM3UFRqMmN6c3RkOUo1VUY0azBJdUdEbVZzM2xjdWg1SEJjYThIeXM2aEpvOG1HbFpMNWN6R2s5bi8vRE1EbDY3RlJraG5QNFNhSDBpZGI5VFEvMERLeFRBTUdhcWpPaEl5ekVqd2ZDQVJleFdlbldyOGlPVkhScDhGM25WZVdvbFRGK002N0xpdi9XNGJXdDk0VEg3b0laUU5lYmZYKzVOKy9Td25Hb1dyMTlWK0pEb2lIRVFLZ1cwMWVuYjZKUXo5Slh2Tm95ZzF3RnJPVmxGc2xwNlRHa1BlN2Rnd2IrWT0ifQ==" } } }
  • Atualize o argumento nextToken com o valor retornado pela consulta anterior da seguinte forma:

    query allPostsByAuthor { allPostsByAuthor( author: "AUTHORNAME" count: 5 nextToken: "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnSExqRnVhVUR3ZUhEZ2QzNGJ2QlFuY0FBQUNqekNDQW9zR0NTcUdTSWIzRFFFSEJxQ0NBbnd3Z2dKNEFnRUFNSUlDY1FZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF5Qkg4Yk1obW9LVEFTZHM3SUNBUkNBZ2dKQ3dISzZKNlJuN3pyYUVKY1pWNWxhSkNtZW1KZ0F5N1dhZkc2UEdTNHpNQzJycTkwZHFJTFV6Z25wck9Gd3pMS3VOQ2JvUXc3VDI5eCtnVExIbGg4S3BqbzB1YjZHQ3FwcDhvNDVmMG9JbDlmdS9JdjNXcFNNSXFKTXZ1MEVGVWs1VzJQaW5jZGlUaVRtZFdYWlU1bkV2NkgyRFBRQWZYYlNnSmlHSHFLbmJZTUZZM0FTdmRIL0hQaVZBb1RCMk1YZkg0eGJOVTdEbjZtRFNhb2QwbzdHZHJEWDNtODQ1UXBQUVNyUFhHemY0WDkyajhIdlBCSWE4Smcrb0RxbHozUVQ5N2FXUXdYWWU2S0h4emI1ejRITXdEdXEyRDRkYzhoMi9CbW10MzRMelVGUVIyaExSZGRaZ0xkdzF5cHJZdFZwY3dEc1d4UURBTzdOcjV2ZEp4VVR2TVhmODBRSnp1REhXREpTVlJLdDJwWmlpaXhXeGRwRmNod1BzQ3d2aVBqMGwrcWFFWU1jMXNQbENkVkFGem43VXJrSThWbS8wWHlwR2xZb3BSL2FkV0xVekgrbGMrYno1ZEM2SnVLVXdtY1EyRXlZeDZiS0Izbi9YdUViWGdFeU5PMWZTdE1rRlhyWmpvMVpzdlYyUFRjMzMrdEs0ZDhkNkZrdjh5VVR6WHhJRkxIaVNsOUx6VVdtT3BCaWhrTFBCT09jcXkyOHh1UmkzOEM3UFRqMmN6c3RkOUo1VUY0azBJdUdEbVZzM2xjdWg1SEJjYThIeXM2aEpvOG1HbFpMNWN6R2s5bi8vRE1EbDY3RlJraG5QNFNhSDBpZGI5VFEvMERLeFRBTUdhcWpPaEl5ekVqd2ZDQVJleFdlbldyOGlPVkhScDhGM25WZVdvbFRGK002N0xpdi9XNGJXdDk0VEg3b0laUU5lYmZYKzVOKy9Td25Hb1dyMTlWK0pEb2lIRVFLZ1cwMWVuYjZKUXo5Slh2Tm95ZzF3RnJPVmxGc2xwNlRHa1BlN2Rnd2IrWT0ifQ==" ) { posts { id title } nextToken } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • As publicações restantes de autoria de AUTHORNAME devem aparecer no painel de resultados à direita do painel de consulta. A aparência deve ser semelhante à seguinte:

    { "data": { "allPostsByAuthor": { "posts": [ { "id": "8", "title": "A series of posts, Volume 8" }, { "id": "5", "title": "A series of posts, Volume 5" }, { "id": "3", "title": "A series of posts, Volume 3" }, { "id": "9", "title": "A series of posts, Volume 9" } ], "nextToken": null } } }

Uso de conjuntos

Até agora o tipo Post foi um objeto de chave/valor plano. Também é possível modelar objetos complexos com o resolvedor do AWS AppSync do DynamoDB, como conjuntos, listas e mapas.

Vamos atualizar o tipo Post para incluir tags. Uma publicação pode ter 0 ou mais tags, que são armazenadas no DynamoDB como um Conjunto de strings. Vamos configurar também algumas mutações para adicionar e remover tags, e uma nova consulta para verificar as publicações com uma tag específica.

  • Escolha a guia Esquema.

  • No painel Esquema, modifique o tipo Post para adicionar um novo campo tags da seguinte forma:

    type Post { id: ID! author: String title: String content: String url: String ups: Int! downs: Int! version: Int! tags: [String!] }
  • No painel Esquema, modifique o tipo Query para adicionar uma nova consulta allPostsByTag da seguinte forma:

    type Query { allPostsByTag(tag: String!, count: Int, nextToken: String): PaginatedPosts! allPostsByAuthor(author: String!, count: Int, nextToken: String): PaginatedPosts! allPost(count: Int, nextToken: String): PaginatedPosts! getPost(id: ID): Post }
  • No painel Esquema, modifique o tipo Mutation para adicionar novas mutações addTag e removeTag da seguinte forma:

    type Mutation { addTag(id: ID!, tag: String!): Post removeTag(id: ID!, tag: String!): Post deletePost(id: ID!, expectedVersion: Int): Post upvotePost(id: ID!): Post downvotePost(id: ID!): Post updatePost( id: ID!, author: String, title: String, content: String, url: String, expectedVersion: Int! ): Post addPost( author: String!, title: String!, content: String!, url: String! ): Post! }
  • Escolha Salvar.

  • No painel Tipos de dados à direita, encontre o campo allPostsByTag recém-criado no tipo Consulta e, em seguida, escolha Anexar.

  • Em Nome da fonte de dados, escolha PostDynamoDBTable.

  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    { "version" : "2017-02-28", "operation" : "Scan", "filter": { "expression": "contains (tags, :tag)", "expressionValues": { ":tag": $util.dynamodb.toDynamoDBJson($context.arguments.tag) } } #if( ${context.arguments.count} ) ,"limit": $util.toJson($context.arguments.count) #end #if( ${context.arguments.nextToken} ) ,"nextToken": $util.toJson($context.arguments.nextToken) #end }
  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    { "posts": $utils.toJson($context.result.items) #if( ${context.result.nextToken} ) ,"nextToken": $util.toJson($context.result.nextToken) #end }
  • Escolha Salvar.

  • No painel Tipos de dados à direita, encontre o campo addTag recém-criado no tipo Mutação e, em seguida, escolha Anexar.

  • Em Nome da fonte de dados, escolha PostDynamoDBTable.

  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    { "version" : "2017-02-28", "operation" : "UpdateItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id) }, "update" : { "expression" : "ADD tags :tags, version :plusOne", "expressionValues" : { ":tags" : { "SS": [ $util.toJson($context.arguments.tag) ] }, ":plusOne" : { "N" : 1 } } } }
  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    $utils.toJson($context.result)
  • Escolha Salvar.

  • No painel Tipos de dados à direita, encontre o campo removeTag recém-criado no tipo Mutação e, em seguida, escolha Anexar.

  • Em Nome da fonte de dados, escolha PostDynamoDBTable.

  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    { "version" : "2017-02-28", "operation" : "UpdateItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id) }, "update" : { "expression" : "DELETE tags :tags ADD version :plusOne", "expressionValues" : { ":tags" : { "SS": [ $util.toJson($context.arguments.tag) ] }, ":plusOne" : { "N" : 1 } } } }
  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    $utils.toJson($context.result)
  • Escolha Salvar.

Chamar a API para trabalhar com tags

Agora que você configurou os resolvedores, AWS AppSync sabe como traduzir solicitações addTag, removeTag e allPostsByTag de entrada recebidas em operações UpdateItem e Scan do DynamoDB.​

Para testar, vamos selecionar uma das publicações criadas anteriormente. Por exemplo, vamos usar uma publicação de autoria da Nadia.

  • Escolha a guia Consultas.

  • No painel Consultas, cole a seguinte consulta:

    query allPostsByAuthor { allPostsByAuthor( author: "Nadia" ) { posts { id title } nextToken } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • Todas as publicações da Nadia devem aparecer no painel de resultados à direita do painel de consulta. A aparência deve ser semelhante à seguinte:

    { "data": { "allPostsByAuthor": { "posts": [ { "id": "10", "title": "The cutest dog in the world" }, { "id": "11", "title": "Did you known...?" } ], "nextToken": null } } }
  • Vamos usar aquela com o título "The cutest dog in the world". Anote seu id pois ele será usado posteriormente.

Agora vamos tentar adicionar uma tag dog.

  • No painel Consultas, cole a mutação a seguir. Também será necessário atualizar o argumento id para o valor anotado anteriormente.

    mutation addTag { addTag(id:10 tag: "dog") { id title tags } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • A publicação é atualizada com a nova tag.

    { "data": { "addTag": { "id": "10", "title": "The cutest dog in the world", "tags": [ "dog" ] } } }

Adicione uma ou mais tags da seguinte forma:

  • Atualize a mutação para alterar o argumento tag para puppy.

    mutation addTag { addTag(id:10 tag: "puppy") { id title tags } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • A publicação é atualizada com a nova tag.

    { "data": { "addTag": { "id": "10", "title": "The cutest dog in the world", "tags": [ "dog", "puppy" ] } } }

Também é possível excluir tags:

  • No painel Consultas, cole a mutação a seguir. Também será necessário atualizar o argumento id para o valor anotado anteriormente.

    mutation removeTag { removeTag(id:10 tag: "puppy") { id title tags } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • A publicação é atualizada e a tag puppy é excluída.

    { "data": { "addTag": { "id": "10", "title": "The cutest dog in the world", "tags": [ "dog" ] } } }

Também é possível pesquisar todas as publicações com uma tag:

  • No painel Consultas, cole a seguinte consulta:

    query allPostsByTag { allPostsByTag(tag: "dog") { posts { id title tags } nextToken } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • Todos as publicações com a tag dog são retornadas da seguinte forma:

    { "data": { "allPostsByTag": { "posts": [ { "id": "10", "title": "The cutest dog in the world", "tags": [ "dog", "puppy" ] } ], "nextToken": null } } }

Uso de listas e mapas

Além de usar conjuntos do DynamoDB, também é possível usar listas e mapas do DynamoDB para modelar dados complexos em um único objeto.

Vamos adicionar a capacidade de adicionar comentários em publicações. Isso será modelado como uma lista de objetos de mapa no objeto Post no DynamoDB.

Observação: em um aplicativo real, os comentários seriam modelados em suas próprias tabelas. Para este tutorial, basta adicioná-los à tabela Post.

  • Escolha a guia Esquema.

  • No painel Esquema, adicione um novo tipo Comment da seguinte forma:

    type Comment { author: String! comment: String! }
  • No painel Esquema, modifique o tipo Post para adicionar um novo campo comments da seguinte forma:

    type Post { id: ID! author: String title: String content: String url: String ups: Int! downs: Int! version: Int! tags: [String!] comments: [Comment!] }
  • No painel Esquema, modifique o tipo Mutation para adicionar uma nova mutação addComment da seguinte forma:

    type Mutation { addComment(id: ID!, author: String!, comment: String!): Post addTag(id: ID!, tag: String!): Post removeTag(id: ID!, tag: String!): Post deletePost(id: ID!, expectedVersion: Int): Post upvotePost(id: ID!): Post downvotePost(id: ID!): Post updatePost( id: ID!, author: String, title: String, content: String, url: String, expectedVersion: Int! ): Post addPost( author: String!, title: String!, content: String!, url: String! ): Post! }
  • Escolha Salvar.

  • No painel Tipos de dados à direita, encontre o campo addComment recém-criado no tipo Mutação e, em seguida, escolha Anexar.

  • Em Nome da fonte de dados, escolha PostDynamoDBTable.

  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    { "version" : "2017-02-28", "operation" : "UpdateItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id) }, "update" : { "expression" : "SET comments = list_append(if_not_exists(comments, :emptyList), :newComment) ADD version :plusOne", "expressionValues" : { ":emptyList": { "L" : [] }, ":newComment" : { "L" : [ { "M": { "author": $util.dynamodb.toDynamoDBJson($context.arguments.author), "comment": $util.dynamodb.toDynamoDBJson($context.arguments.comment) } } ] }, ":plusOne" : $util.dynamodb.toDynamoDBJson(1) } } }

    Essa expressão de atualização anexará uma lista que contém o novo comentário à lista comments existente. Se a lista ainda não existir, ela será criada.

  • Em Configurar o modelo de mapeamento da solicitação, cole o seguinte:

    $utils.toJson($context.result)
  • Escolha Salvar.

Chamar a API para adicionar um comentário

Agora que você configurou os resolvedores, o AWS AppSync sabe como traduzir as solicitações addComment recebidas em operações UpdateItem do DynamoDB.

Vamos testar adicionando um comentário à mesma publicação na qual as tags foram adicionadas.

  • Escolha a guia Consultas.

  • No painel Consultas, cole a seguinte consulta:

    mutation addComment { addComment( id:10 author: "Steve" comment: "Such a cute dog." ) { id comments { author comment } } }
  • Escolha Executar consulta (o botão de reprodução laranja).

  • Todas as publicações da Nadia devem aparecer no painel de resultados à direita do painel de consulta. A aparência deve ser semelhante à seguinte:

    { "data": { "addComment": { "id": "10", "comments": [ { "author": "Steve", "comment": "Such a cute dog." } ] } } }

Se você executar a solicitação várias vezes, vários comentários serão anexados à lista.

Conclusão

Neste tutorial, você criou uma API que permite manipular Objetos de publicação no DynamoDB usando o AWS AppSync e o GraphQL. Para obter mais informações, consulte a Referência do modelo de mapeamento do resolvedor.

Para limpar, você pode excluir a API GraphQL do AppSync do console.

Para excluir a tabela do DynamoDB e o perfil do IAM criado nesse tutorial, execute o seguinte para excluir a pilha do AWSAppSyncTutorialForAmazonDynamoDB, ou acesse o console do AWS CloudFormation e exclua a pilha:

aws cloudformation delete-stack \ --stack-name AWSAppSyncTutorialForAmazonDynamoDB