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.
-
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 dePost
. -
Um perfil do IAM e política gerenciada pelo IAM associada para permitir que o AWS AppSync interaja com a tabela de
Post
.
-
-
Para ver mais detalhes sobre a pilha e os recursos criados, execute o seguinte comando da CLI:
aws cloudformation describe-stacks --stack-name AWSAppSyncTutorialForAmazonDynamoDB
-
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:
-
Faça login no AWS Management Console e abra o console do AppSync
. -
No painel de APIs, escolha Criar API.
-
-
Na janela Personalizar sua API ou importar a partir do Amazon DynamoDB, escolha Criar a partir do zero.
-
Escolha Iniciar à direita da mesma janela.
-
-
No campo Nome da API, defina o nome da API para
AWSAppSyncTutorial
. -
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.
-
Faça login no AWS Management Console e abra o console do AppSync
. -
No painel de APIs, escolha a API que você acabou de criar.
-
-
Na barra lateral, escolha Esquema.
-
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! }
-
-
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:
-
Faça login no AWS Management Console e abra o console do AppSync
. -
No painel de APIs, escolha sua API GraphQL.
-
Na barra lateral, escolha Fontes de dados.
-
-
Escolha Criar fonte de dados.
-
Para Nome da fonte de dados, insira em
PostDynamoDBTable
. -
Para o tipo de fonte de dados, escolha Tabela do Amazon DynamoDB.
-
Para Região, escolha US-WEST-2.
-
Em Nome da tabela, escolha a tabela AppSyncTutorial-post do DynamoDB.
-
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:*" ] } ] }
-
-
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 tipoMutation
. Esse resolvedor será invocado quando o chamador chamarmutation { 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 DynamoDBAppSyncTutorial-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:
-
Faça login no AWS Management Console e abra o Console do AppSync
. -
No painel de APIs, escolha sua API GraphQL.
-
Na barra lateral, escolha Fontes de dados.
-
-
Escolha Criar fonte de dados.
-
Para Nome da fonte de dados, insira em
PostDynamoDBTable
. -
Para o tipo de fonte de dados, escolha Tabela do Amazon DynamoDB.
-
Para Região, escolha US-WEST-2.
-
Em Nome da tabela, escolha a tabela AppSyncTutorial-post do DynamoDB.
-
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:*" ] } ] }
-
-
Escolha Criar.
-
Escolha a guia Esquema.
-
No painel Tipos de dados à direita, encontre o campo addPost 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" : "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 parteS
indica ao AWS AppSync e ao DynamoDB que o valor será uma string. O valor real é preenchido a partir do argumentoauthor
. Da mesma forma, o campoversion
é um campo de número pois ele usaN
para o tipo. Finalmente, você também está inicializando os camposups
,downs
eversion
.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 oid: ID!
fora da definição do esquema deaddPost()
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.
-
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 tipoPost
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. -
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çãoupdatePost
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çãoupdate
. Ela diz para definir oauthor
, otitle
, ocontent
e os atributos de url e, em seguida, incrementar o campoversion
. 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 campoexpressionValues
. Finalmente, o DynamoDB tem palavras reservadas que não podem aparecer noexpression
. Por exemplo,url
é uma palavra reservada, então, para atualizar o campourl
é possível usar espaços reservados de nome e defini-los no campoexpressionNames
.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
.
-
Escolha a guia Esquema.
-
No painel Esquema, modifique o campo
updatePost
no tipoMutation
e remova os pontos de exclamação dos argumentosauthor
,title
,content
eurl
, mantendo o campoid
como está. Isso os tornará argumento opcional. Além disso, adicione um novo argumentoexpectedVersion
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! }
-
Escolha Salvar.
-
No painel Tipos de dados, encontre o campo updatePost no tipo Mutação.
-
Escolha PostDynamoDBTable para abrir o resolvedor existente.
-
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) } } }
-
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 era2
, que correspondia ao argumentoexpectedVersion
. A solicitação foi bem-sucedida, o que significa que o campoversion
foi incrementado no DynamoDB para3
. -
Na segunda vez que a solicitação foi executada, o valor do campo
version
da publicação no DynamoDB era3
, que não correspondeu ao argumentoexpectedVersion
.
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çõesupvotePost
edownvotePost
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
eversion
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
eversion
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çãodeletePost
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 argumentoexpectedVersion
na solicitação, o modelo adiciona uma condição que permite que a solicitaçãoDeleteItem
seja bem-sucedida somente se o item já estiver excluído ou se o atributoversion
da publicação no DynamoDB corresponder exatamente aoexpectedVersion
. Se omitido, nenhuma expressão de condição será especificada na solicitaçãoDeleteItem
. Ele será bem-sucedida independentemente do valor deversion
, 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 aoexpectedValue
especificado nos argumentos. O valor atual do objeto é retornada no campodata
na seçãoerrors
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 consultaallPost
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, enextToken
, que pode ser usado para recuperar o próximo conjunto de resultados, (você mostrará de onde vem o valor paranextToken
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
é umPaginatedPosts
, 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 chamaitems
nos resultados do resolvedor do DynamoDB do AWS AppSync, mas se chamaposts
emPaginatedPosts
. -
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 onextToken
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 consultaallPostsByAuthor
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 consultaallPost
. -
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 enextToken
, que pode ser usado para recuperar o próximo conjunto de resultados (o valor paranextToken
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 campotags
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 consultaallPostsByTag
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çõesaddTag
eremoveTag
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 seuid
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
parapuppy
.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 campocomments
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çãoaddComment
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