本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
教程:DynamoDB 解析器
本教程展示了如何将自己的Amazon DynamoDB 表引入 GraphQL APIAmazon AppSync 并将其连接到 GraphQL API。
您可以让他人代您Amazon AppSync 配置 DynamoDB 资源。如果您愿意,也可以创建数据源和解析程序,将现有的表连接到 GraphQL 架构。在这两种情况下,您都可以通过 GraphQL 语句读写您的 DynamoDB 数据库,并订阅实时数据。
要将 GraphQL 语句转换为 DynamoDB 操作,并将响应转换回 GraphQL,需要完成一些特定的配置步骤。本教程通过一些现实世界的场景和数据访问模式介绍了配置过程。
设置 DynamoDB p
要开始本教程,首先需要按照以下步骤配置Amazon资源。
-
在 CLI 中使用以下Amazon CloudFormation模板配置Amazon资源:
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
或者,您可以在您的Amazon账户中在美国西部 2(俄勒冈)地区启动以下Amazon CloudFormation堆栈。
这会创建以下内容:
-
一个名
AppSyncTutorial-Post
为的 DynamoDB 表用于保存Post
数据。 -
一个 IAM 角色以及关联的 IAM 托管策略,允许 Amazon AppSync 与
Post
表交互。
-
-
要了解堆栈和所创建资源的更多详细信息,请运行以下 CLI 命令:
aws cloudformation describe-stacks --stack-name AWSAppSyncTutorialForAmazonDynamoDB
-
稍后要删除资源,您可以运行以下操作:
aws cloudformation delete-stack --stack-name AWSAppSyncTutorialForAmazonDynamoDB
创建一个 GrapQL API
要在 Amazon AppSync 中创建 GraphQL API:
-
登录 Amazon Web Services Management Console并打开 AppSync 控制台
。 -
在 API 控制面板中,选择创建 API。
-
-
在 “自定义 API 或从 Amazon DynamoDB 导入” 窗口下,选择 “从头开始构建”。
-
选择同一窗口右侧的 “开始”。
-
-
在 API 名称字段中,将 API 的名称设置为
AWSAppSyncTutorial
。 -
选择 Create(创建)。
Amazon AppSync 控制台会使用 API 密钥身份验证模式为您创建新的 GraphQL API。您可以根据本教程后面的说明,使用控制台设置 GraphQL API 的其余部分,并针对它运行查询。
定义基本的帖子 API
现在您已经创建了Amazon AppSync GraphQL API,您可以设置一个基本架构,允许对帖子数据进行基本创建、检索和删除。
-
登录 Amazon Web Services Management Console并打开 AppSync 控制台
。 -
在 API 控制面板中,选择您刚刚创建的 API。
-
-
在侧栏中,选择架构。
-
在 “架构” 窗格中,将内容替换为以下代码:
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! }
-
-
选择 Save(保存)。
此架构定义 Post
类型,执行操作以添加并获取 Post
对象。
为 DynamoDB 表配置数据源
接下来,将架构中定义的查询和变更链接到AppSyncTutorial-Post
DynamoDB 表。
首先,Amazon AppSync 需要知道您的表。要实现此目的,需要在 Amazon AppSync 中设置数据源:
-
登录 Amazon Web Services Management Console并打开 AppSync 控制台
。 -
在 API 控制面板中,选择你的 GraphQL API。
-
在侧栏中,选择数据源。
-
-
选择 Create data source。
-
在数据源名称中,输入
PostDynamoDBTable
。 -
对于数据源类型,选择 Amazon DynamoDB 表。
-
对于区域,选择 US-WEST-2。
-
对于表名称,选择 AppSyncTutorial-Pos t DynamoDB 表。
-
创建新的 IAM 角色(推荐)或选择具有
lambda:invokeFunction
IAM 权限的现有角色。现有角色需要信任策略,如附加数据源部分所述。以下是一个 IAM 策略,该策略具有执行操作所需的权限:
{ "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:*" ] } ] }
-
-
选择 Create(创建)。
设置 addPost 解析器 (DynamoDB PutItem)
获Amazon AppSync 知 DynamoDB 表后,您可以通过定义解析器将其链接到单个查询和突变。您创建的第一个解析器是addPost
解析器,它使您能够在AppSyncTutorial-Post
DynamoDB 表中创建帖子。
解析程序具有以下组件:
-
GraphQL 架构中的位置,用于附加解析程序。在本例中,您将设置
addPost
类型的Mutation
字段的解析程序。调用者调用mutation { addPost(...){...} }
时,将调用此解析程序。 -
此解析程序所用的数据源。在本例中,您要使用之前定义的
PostDynamoDBTable
数据源,这样您就可以在AppSyncTutorial-Post
DynamoDB 表中添加条目。 -
请求映射模板。请求映射模板的目的是将调用者的传入请求转换为指令,这样 Amazon AppSync 就可以针对 DynamoDB 执行操作。
-
响应映射模板。响应映射模板的任务是将 DynamoDB 的响应转换回 GraphQL 期待获得的内容。如果 DynamoDB 中的数据形态与 GraphQL 中的
Post
类型不同,此模板很有用。但在此例中它们的形态相同,所以只用于传递数据。
设置解析程序:
-
登录 Amazon Web Services Management Console并打开 AppSync 控制台
。 -
在 API 控制面板中,选择你的 GraphQL API。
-
在侧栏中,选择数据源。
-
-
选择 Create data source。
-
在数据源名称中,输入
PostDynamoDBTable
。 -
对于数据源类型,选择 Amazon DynamoDB 表。
-
对于区域,选择 US-WEST-2。
-
对于表名称,选择 AppSyncTutorial-Pos t DynamoDB 表。
-
创建新的 IAM 角色(推荐)或选择具有
lambda:invokeFunction
IAM 权限的现有角色。现有角色需要信任策略,如附加数据源部分所述。以下是一个 IAM 策略,该策略具有执行操作所需的权限:
{ "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:*" ] } ] }
-
-
选择 Create(创建)。
-
选择 Schema (架构) 选项卡。
-
在右侧的 “数据类型” 窗格中,找到 “突变” 类型上的 addPos t t 字段,然后选择 “附加”。
-
在数据源名称中,选择 PostDynamodbTable。
-
在 Configure the request mapping template (配置请求映射模板) 中,粘贴以下内容:
{ "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 } } }
注意:为所有键和属性值指定了类型。例如,您将
author
字段设置为{ "S" : "${context.arguments.author}" }
。该S
部分向Amazon AppSync 和 DynamoDB 表示该值将是字符串值。实际的值由author
参数填充。与此类似,version
字段是一个数字字段,因为它使用N
作为类型。最后,您还将初始化ups
、downs
和version
字段。在本教程中,您指定了 GraphQL
ID!
类型(索引插入到 DynamoDB 的新项目)作为客户端参数的一部分。 Amazon AppSync附带了一个名为的自动生成 ID$utils.autoId()
的实用程序,你也可以用它的形式使用"id" : { "S" : "${$utils.autoId()}" }
。然后,就可以在id: ID!
的架构定义中省去addPost()
,因为它将自动插入。您不会在本教程中使用这种方法,但是在写入 DynamoDB 表时应将其视为一种很好的做法。有关映射模板的更多信息,请参阅 解析程序映射模板概述参考文档。有关 GetItem 请求映射的更多信息,请参阅GetItem参考文档。有关类型的更多信息,请参阅类型系统(请求映射)参考文档。
-
在 Configure the response mapping template (配置响应映射模板) 中,粘贴以下内容:
$utils.toJson($context.result)
注意:由于
AppSyncTutorial-Post
表中的数据形态与 GraphQL 中Post
类型的形态完全匹配,响应映射模板只会直接传递结果。还请注意,此教程中的所有示例均使用同一响应映射模板,所以您只需创建一个文件。 -
选择 Save(保存)。
调用 API 来添加文章
现在解析器已经设置好了,Amazon AppSync 可以将传入的addPost
突变转换为 DynamoDB PutItem 操作。现在,您可以运行一个更改,在表中添加内容。
-
选择 Queries 选项卡。
-
在 Queries (查询) 窗格中,粘贴以下更改:
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 } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
新创建的文章的结果应出现在查询窗格右侧的结果窗格中。如下所示:
{ "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 } } }
以下是具体过程:
-
Amazon AppSync 收到了
addPost
突变请求。 -
Amazon AppSync 接收了请求和请求映射模板,并生成了请求映射文档。如下所示:
{ "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 } } }
-
Amazon AppSync 使用请求映射文档生成和执行了 DynamoDB
PutItem
请求。 -
Amazon AppSync 获取了
PutItem
请求的结果并将其转换回 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 }
-
通过响应映射文档进行传递,没有变化。
-
在 GraphQL 响应中返回新创建的对象。
设置 getPost 解析器 (DynamoDB GetItem)
现在,您可以向AppSyncTutorial-Post
DynamoDB 表添加数据,您需要设置getPost
查询,这样它才能从AppSyncTutorial-Post
表中检索数据。为了实现此目的,您要设置另一解析程序。
-
选择 Schema (架构) 选项卡。
-
在右侧的数据类型窗格中,找到查询类型上的 getPost 字段,然后选择附加。
-
在数据源名称中,选择 PostDynamodbTable。
-
在 Configure the request mapping template (配置请求映射模板) 中,粘贴以下内容:
{ "version" : "2017-02-28", "operation" : "GetItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id) } }
-
在 Configure the response mapping template (配置响应映射模板) 中,粘贴以下内容:
$utils.toJson($context.result)
-
选择 Save(保存)。
调用 API 以获取文章
现在解析器已经设置好了,Amazon AppSync 知道如何将传入的getPost
查询转换为 DynamoDBGetItem
操作。现在,您可以运行查询,检索之前创建的文章。
-
选择 Queries 选项卡。
-
在Queries (查询) 窗格中粘贴以下内容:
query getPost { getPost(id:123) { id author title content url ups downs version } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
从 DynamoDB 检索到的帖子应显示在查询窗格右侧的结果窗格中。如下所示:
{ "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 } } }
以下是具体过程:
-
Amazon AppSync 收到了
getPost
查询请求。 -
Amazon AppSync 接收了请求和请求映射模板,并生成了请求映射文档。如下所示:
{ "version" : "2017-02-28", "operation" : "GetItem", "key" : { "id" : { "S" : "123" } } }
-
Amazon AppSync 使用请求映射文档生成和执行了 DynamoDB GetItem 请求。
-
Amazon AppSync 获取了
GetItem
请求的结果并将其转换回 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 }
-
通过响应映射文档进行传递,没有变化。
-
在响应中返回检索到的对象。
或者,使用以下示例:
query getPost { getPost(id:123) { id author title } }
如果您的getPost
查询只需要id
author
、和title
,则可以将请求映射模板更改为使用投影表达式仅指定您想要从 DynamoDB 表中获取的属性,以避免从 DynamoDB 向其传输不必要的数据Amazon AppSync。例如,请求映射模板可能如下所示:
{ "version" : "2017-02-28", "operation" : "GetItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id) }, "projection" : { "expression" : "#author, id, title", "expressionNames" : { "#author" : "author"} } }
创建 UpdatePost 变异 (DynamoDB UpdateItem)
到目前为止,您可以在 DynamoDB 中创建和检索Post
对象。现在,您要设置一项新的更改,以便更新对象。你将使用 UpdateItem DynamoDB 操作来完成此操作。
-
选择 Schema (架构) 选项卡。
-
在 Schema (架构) 窗格中修改
Mutation
类型,添加新的updatePost
更改,如下所示:type Mutation { updatePost( id: ID!, author: String!, title: String!, content: String!, url: String! ): Post addPost( author: String! title: String! content: String! url: String! ): Post! }
-
选择 Save(保存)。
-
在右侧的数据类型窗格中,找到突变类型上新创建的 UpdatePos t 字段,然后选择 Att ach。
-
在数据源名称中,选择 PostDynamodbTable。
-
在 Configure the request mapping template (配置请求映射模板) 中,粘贴以下内容:
{ "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 } } } }
注意:此解析器使用的是 DynamoDB UpdateItem,这与 PutItem 操作有很大不同。你不是写整篇文章,而是让 DynamoDB 更新某些属性。通过将和DynamoDB 更新表达式结合使用来执行此操作。表达式本身是在
expression
部分的update
字段中指定的。它会设置author
、title
、content
和 URL 属性,还会递增version
字段。要使用的值不会出现在表达式本身;表达式中的占位符名称以冒号打头,并在expressionValues
字段中进行定义。最后,DynamoDB 的保留字不能出现在中expression
。例如,url
是保留关键字,所以要更新url
字段,您可使用名称占位符,并在expressionNames
字段中定义它们。有关
UpdateItem
请求映射的更多信息,请参阅UpdateItem参考文档。有关如何编写更新表达式的更多信息,请参阅 DynamoDB UpdateExpressions 文档。 -
在 Configure the response mapping template (配置响应映射模板) 中,粘贴以下内容:
$utils.toJson($context.result)
调用 API 以更新文章
现在解析器已经设置好了,Amazon AppSync 知道如何将传入的update
突变转换为 DynamoDBUpdate
操作。现在,您可以运行更改,以更新您之前写入的项目。
-
选择 Queries 选项卡。
-
在 Queries (查询) 窗格中,粘贴以下更改。您还需要更新
id
参数,改为您之前记下的值。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 } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
DynamoDB 中更新的帖子应显示在查询窗格右侧的结果窗格中。如下所示:
{ "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 } } }
在此示例中,未修改ups
和downs
字段,因为请求映射模板没有要求Amazon AppSync 和 DynamoDB 对这些字段执行任何操作。此外,该version
字段增加了 1,因为您要求Amazon AppSync DynamoDB 向该version
字段添加 1。
修改 UpdatePost 解析器 (DynamoDB UpdateItem)
updatePost
更改看上去不错,但它有两个主要问题:
-
如果您只希望更新一个字段,则必须更新所有字段。
-
如果两个人同时修改对象,您可能会丢失信息。
为了解决这些问题,您要修改 updatePost
更改,做到只修改请求中指定的参数,然后在 UpdateItem
操作中添加条件。
-
选择 Schema (架构) 选项卡。
-
在 Schema (架构) 窗格中修改
Mutation
类型中的updatePost
字段,删除author
、title
、content
和url
参数的感叹号,确保id
字段不变。这样它们就会成为可选参数。还要新增一个必需expectedVersion
参数。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! }
-
选择 Save(保存)。
-
在右侧的 “数据类型” 窗格中,找到 “突变” 类型上的 UpdatePos t 字段。
-
选择 PostDynamodbTable 打开现有的解析器。
-
在 Configure the request mapping template (配置请求映射模板) 中修改请求映射模板,如下所示:
{ "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) } } }
-
选择 Save(保存)。
此模板是一个更复杂的示例。它演示了映射模板的强大功能和灵活性。它遍历所有参数,跳过 id
和 expectedVersion
。如果参数设置为某个值,它会要求Amazon AppSync 和 DynamoDB 更新 DynamoDB 中该对象的该属性。如果该属性设置为空,它会要求Amazon AppSync 和 DynamoDB 从帖子对象中删除该属性。如果未指定参数,该属性会保留原样。它还会递增 version
字段。
还有一个新的 condition
部分。条件表达式使您能够根据执行操作之前已在 DynamoDB 中的对象的状态告知Amazon AppSync DynamoDB 请求是否应成功。在这种情况下,只有当 DynamoDB 中当前项目的version
字段与expectedVersion
参数完全匹配时,您才希望UpdateItem
请求成功。
有关条件表达式的更多信息,请参阅条件表达式参考文档。
调用 API 以更新文章
让我们尝试用新的解析程序更新 Post
对象:
-
选择 Queries 选项卡。
-
在 Queries (查询) 窗格中,粘贴以下更改。您还需要更新
id
参数,改为您之前记下的值。mutation updatePost { updatePost( id:123 title: "An empty story" content: null expectedVersion: 2 ) { id author title content url ups downs version } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
DynamoDB 中更新的帖子应显示在查询窗格右侧的结果窗格中。如下所示:
{ "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 } } }
在此请求中,您要求Amazon AppSync 和 DynamoDB 仅更新title
和content
字段。它不会处理所有其他字段(除了递增 version
字段)。您将 title
属性设为新值,并删除文章的 content
属性。author
、url
、ups
和 downs
字段没有变化。
请尝试再次执行更改请求,保持请求完全不变。您可以看到类似以下内容的响应:
{ "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)" } ] }
请求失败,因为条件表达式评估为 false:
-
首次运行请求时,DynamoDB 中帖子
version
字段的值为2
,该值与expectedVersion
参数相匹配。请求成功,这意味着该version
字段在 DynamoDB 中递增为3
。 -
第二次运行请求时,DynamoDB 中帖子
version
字段的值为3
,该值与expectedVersion
参数不匹配。
这种模式通常被称为乐观锁。
Amazon AppSync DynamoDB 解析器的一个功能是它返回 DynamoDB 中帖子对象的当前值。您可以在 GraphQL 响应的 data
部分的 errors
字段中找到这个值。您的应用程序可以利用此信息决定应如何继续。在这种情况下,您可以看到 DynamoDB 中对象的version
字段设置为3
,因此您只需将expectedVersion
参数更新为3
,请求就会再次成功。
有关如何处理条件检查失败的更多信息,请参阅条件表达式映射模板参考文档。
创建 upvotePost 和 downVotePost 突变 (dynamoDB UpdateItem)
Post
类型有 ups
和 downs
字段,用于记录赞同投票和反对投票,但现在还无法通过 API 使用它们。让我们添加一些更改,对文章进行赞同和反对投票。
-
选择 Schema (架构) 选项卡。
-
在 Schema (架构) 窗格中修改
Mutation
类型,添加新的upvotePost
和downvotePost
更改,如下所示: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! }
-
选择 Save(保存)。
-
在右侧的 “数据类型” 窗格中,在 “突变” 类型上找到新创建的 upvotePos t 字段,然后选择 “附加”。
-
在数据源名称中,选择 PostDynamodbTable。
-
在 Configure the request mapping template (配置请求映射模板) 中,粘贴以下内容:
{ "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 } } } }
-
在 Configure the response mapping template (配置响应映射模板) 中,粘贴以下内容:
$utils.toJson($context.result)
-
选择 Save(保存)。
-
在右侧的数据类型窗格中,找到突变类型上新创建的
downvotePost
字段,然后选择 Attac h。 -
在数据源名称中,选择 PostDynamodbTable。
-
在 Configure the request mapping template (配置请求映射模板) 中,粘贴以下内容:
{ "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 } } } }
-
在 Configure the response mapping template (配置响应映射模板) 中,粘贴以下内容:
$utils.toJson($context.result)
-
选择 Save(保存)。
调用 API,为文章投赞同票或反对票
现在,新的解析器已经设置完毕,Amazon AppSync 知道如何将传入upvotePost
或downvote
突变转换为 DynamoDB UpdateItem 操作。现在您可以运行更改,为之前创建的文章投赞同票或反对票。
-
选择 Queries 选项卡。
-
在 Queries (查询) 窗格中,粘贴以下更改。您还需要更新
id
参数,改为您之前记下的值。mutation votePost { upvotePost(id:123) { id author title content url ups downs version } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
该帖子已在 DynamoDB 中更新,应显示在查询窗格右侧的结果窗格中。如下所示:
{ "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 } } }
-
再选择几次 (执行查询) 按钮。您应看到,每次您执行查询时,
ups
和version
字段均会递增 1。 -
更改查询以调用
downvotePost
更改,如下所示:mutation votePost { downvotePost(id:123) { id author title content url ups downs version } }
-
选择 Execute query (执行查询)(橙色播放按钮)。这次您应看到,每次您执行查询时,
downs
和version
字段均会递增 1。{ "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 } } }
设置 DeletePost 解析器 (DynamoDB DeleteItem)
接下来您要设置的更改是删除一个文章。你将使用DeleteItem
DynamoDB 操作来完成此操作。
-
选择 Schema (架构) 选项卡。
-
在 Schema (架构) 窗格中修改
Mutation
类型,添加新的deletePost
更改,如下所示: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! }
这次您将
expectedVersion
字段设为可选,稍后在添加请求映射模板时将对此进行说明。 -
选择 Save(保存)。
-
在右侧的数据类型窗格中,找到突变类型上新创建的删除字段,然后选择 Attac h。
-
在数据源名称中,选择 PostDynamodbTable。
-
在 Configure the request mapping template (配置请求映射模板) 中,粘贴以下内容:
{ "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 }
注意:
expectedVersion
参数是可选的。如果调用者在请求中设置了expectedVersion
参数,则模板会添加一个条件,该条件仅在项目已被删除或者 DynamoDB 中帖子的version
属性完全匹配时才允许DeleteItem
请求成功expectedVersion
。如果未设置此参数,则DeleteItem
请求中不指定条件表达式。无论该项目的值如何,或者该项目是否存在于 DynamoDB 中,它都会成功。version
-
在 Configure the response mapping template (配置响应映射模板) 中,粘贴以下内容:
$utils.toJson($context.result)
注意:即使您要删除一个项目,如果该项目不是已经删除,还是可以返回要删除的项目。
-
选择 Save(保存)。
有关DeleteItem
请求映射的更多信息,请参阅DeleteItem参考文档。
调用 API 以删除文章
现在解析器已经设置好了,Amazon AppSync 知道如何将传入的delete
突变转换为 DynamoDBDeleteItem
操作。现在,您可以运行更改,从表中删除一些内容。
-
选择 Queries 选项卡。
-
在 Queries (查询) 窗格中,粘贴以下更改。您还需要更新
id
参数,改为您之前记下的值。mutation deletePost { deletePost(id:123) { id author title content url ups downs version } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
该帖子已从 DynamoDB 中删除。请注意,Amazon AppSync 返回已从 DynamoDB 中删除的项目的值,该项目应出现在查询窗格右侧的结果窗格中。如下所示:
{ "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 } } }
只有调用的 deletePost
将项目从 DynamoDB 中实际删除,才会返回值。
-
再次选择 Execute query (执行查询)。
-
调用仍是成功的,但没有返回值。
{ "data": { "deletePost": null } }
现在让我们尝试删除一篇文章,但这次要指定 expectedValue
。但首先您需要创建一个新文章,因为您刚刚删除了一直在使用的文章。
-
在 Queries (查询) 窗格中,粘贴以下更改:
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 } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
新创建的文章的结果应出现在查询窗格右侧的结果窗格中。记下新建对象的
id
,因为一会您将用到它。如下所示:{ "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 } } }
现在让我们尝试删除这个文章,但放入 expectedVersion
的错误值:
-
在 Queries (查询) 窗格中,粘贴以下更改。您还需要更新
id
参数,改为您之前记下的值。mutation deletePost { deletePost( id:123 expectedVersion: 9999 ) { id author title content url ups downs version } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
{ "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)" } ] }
请求失败,因为条件表达式的计算结果为 false:DynamoDB 中帖子的值与参数中
expectedValue
指定的值不匹配。version
对象的当前值返回到 GraphQL 响应的data
部分的errors
字段中。 -
重试请求,但更正
expectedVersion
:mutation deletePost { deletePost( id:123 expectedVersion: 1 ) { id author title content url ups downs version } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
这次请求成功,并返回从 DynamoDB 中删除的值:
{ "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 } } }
-
再次选择 Execute query (执行查询)。
-
调用仍然成功,但这次没有返回任何值,因为该帖子已在 DynamoDB 中删除。
{ "data": { "deletePost": null } }
设置 allPost 解析程序 (DynamoDB Scan)
到目前为止,只有当您知道您想查看的每个帖子的 id
时,API 才有用。让我们添加新的解析程序,它可以返回表中的所有文章。
-
选择 Schema (架构) 选项卡。
-
在 Schema (架构) 窗格中修改
Query
类型,添加新的allPost
查询,如下所示:type Query { allPost(count: Int, nextToken: String): PaginatedPosts! getPost(id: ID): Post }
-
添加新
PaginationPosts
类型:type PaginatedPosts { posts: [Post!]! nextToken: String }
-
选择 Save(保存)。
-
在右侧的数据类型窗格中,在查询类型上找到新创建的 allPos t t 字段,然后选择 Attac h。
-
在数据源名称中,选择 PostDynamodbTable。
-
在 Configure the request mapping template (配置请求映射模板) 中,粘贴以下内容:
{ "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 }
此解析程序有两个可选参数:
count
指定单次调用可返回的项目数量上限;nextToken
可用于检索下一组结果(稍后您将展示nextToken
的值来自何处)。 -
在 Configure the response mapping template (配置响应映射模板) 中,粘贴以下内容:
{ "posts": $utils.toJson($context.result.items) #if( ${context.result.nextToken} ) ,"nextToken": $util.toJson($context.result.nextToken) #end }
注意:此响应映射模板与目前我们所用到的其他模板均不同。
allPost
查询的结果是PaginatedPosts
,其中包含一组文章和一个分页标记。此对象的形态与 Amazon AppSync DynamoDB 解析程序返回的对象不同:文章列表在 Amazon AppSync DynamoDB 解析程序的结果中称为items
,但在PaginatedPosts
中称为posts
。 -
选择 Save(保存)。
有关 Scan
请求映射的更多信息,请参阅 Scan 参考文档。
调用 API 以扫描所有文章
现在解析器已经设置好了,Amazon AppSync 知道如何将传入的allPost
查询转换为 DynamoDBScan
操作。现在您可以扫描整个表,检索所有文章。
在进行尝试之前,您需要在表中填充一些数据,因为您已经删除了之前使用的所有内容。
-
选择 Queries 选项卡。
-
在 Queries (查询) 窗格中,粘贴以下更改:
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 } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
现在,让我们扫描表,每次返回 5 个结果。
-
在Queries (查询) 窗格中粘贴以下查询:
query allPost { allPost(count: 5) { posts { id title } nextToken } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
最前面的 5 个文章应出现在查询窗格右侧的结果窗格中。如下所示:
{ "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=" } } }
您可以看到 5 个结果,还有一个 nextToken
,可用于获得下一组结果。
-
更新
allPost
查询,加入上一组结果的nextToken
:query allPost { allPost( count: 5 nextToken: "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnRlluNktJRWl6V0ZlR3hJOVJkaStrZUFBQUI1akNDQWVJR0NTcUdTSWIzRFFFSEJxQ0NBZE13Z2dIUEFnRUFNSUlCeUFZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF5cW8yUGFSZThnalFpemRCTUNBUkNBZ2dHWk1JODhUNzhIOFVUZGtpdFM2ZFluSWRyVDg4c2lkN1RjZzB2d1k3VGJTTWpSQ2U3WjY3TkUvU2I1dWNETUdDMmdmMHErSGJSL0pteGRzYzVEYnE1K3BmWEtBdU5jSENJdWNIUkJ0UHBPWVdWdCtsS2U5L1pNcWdocXhrem1RaXI1YnIvQkt6dU5hZmJCdE93NmtoM2Jna1BKM0RjWWhpMFBGbmhMVGg4TUVGSjBCcXg3RTlHR1V5N0tUS0JLZlV3RjFQZ0JRREdrNzFYQnFMK2R1S2IrVGtZZzVYMjFrc3NyQmFVTmNXZmhTeXE0ZUJHSWhqZWQ5c3VKWjBSSTc2ZnVQdlZkR3FLNENjQmxHYXhpekZnK2pKK1FneEU1SXduRTNYYU5TR0I4QUpmamR2bU1wbUk1SEdvWjlMUUswclczbG14RDRtMlBsaTNLaEVlcm9pem5zcmdINFpvcXIrN2ltRDN3QkJNd3BLbGQzNjV5Nnc4ZnMrK2FnbTFVOUlKOFFrOGd2bEgySHFROHZrZXBrMWlLdWRIQ25LaS9USnBlMk9JeEVPazVnRFlzRTRUU09HUlVJTkxYY2MvdW1WVEpBMUthV2hWTlAvdjNlSnlZQUszbWV6N2h5WHVXZ1BkTVBNWERQdTdjVnVRa3EwK3NhbGZOd2wvSUx4bHNyNDVwTEhuVFpyRWZvVlV1bXZ5S2VKY1RUU1lET05hM1NwWEd2UT09In0=" ) { posts { id author } nextToken } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
其余的 4 个文章应出现在查询窗格右侧的结果窗格中。在这一组结果中没有
nextToken
,因为您已经找到了所有的 9 个文章,没有其他内容了。如下所示:{ "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 } } }
设置 allPostsBy作者解析器(DynamoDB 查询)
除了扫描 DynamoDB 中的所有帖子外,您还可以查询 DynamoDB 以检索特定作者创建的帖子。您之前创建的 DynamoDB 表已经有一个GlobalSecondaryIndex
调用,author-index
您可以与 DynamoDBQuery
操作一起使用来检索特定作者创建的所有帖子。
-
选择 Schema (架构) 选项卡。
-
在 Schema (架构) 窗格中修改
Query
类型,添加新的allPostsByAuthor
查询,如下所示:type Query { allPostsByAuthor(author: String!, count: Int, nextToken: String): PaginatedPosts! allPost(count: Int, nextToken: String): PaginatedPosts! getPost(id: ID): Post }
注意:这次使用与
allPost
查询相同的PaginatedPosts
类型。 -
选择 Save(保存)。
-
在右侧的 “数据类型” 窗格中,找到查询类型上新创建的 “allPostsBy作者” 字段,然后选择 “附加”。
-
在数据源名称中,选择 PostDynamodbTable。
-
在 Configure the request mapping template (配置请求映射模板) 中,粘贴以下内容:
{ "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 }
与
allPost
解析程序相似,此解析程序也有两个可选参数:count
指定单次调用可返回的项目数量上限;nextToken
可用于检索下一组结果(nextToken
的值可从上次调用获得)。 -
在 Configure the response mapping template (配置响应映射模板) 中,粘贴以下内容:
{ "posts": $utils.toJson($context.result.items) #if( ${context.result.nextToken} ) ,"nextToken": $util.toJson($context.result.nextToken) #end }
注意:此处使用的响应映射模板与
allPost
解析程序中所用的相同。 -
选择 Save(保存)。
了解有关 Query
请求映射的更多信息,请参阅 Query 参考文档。
调用 API 以查询某一作者的所有文章
现在解析器已经设置好了,Amazon AppSync 知道如何将传入的allPostsByAuthor
突变转换为针对author-index
索引的 DynamoDBQuery
操作。现在,您可以查询表,检索某一作者的所有文章。
但首先我们需要在表中再填充一些文章,因为目前所有文章都是同一作者。
-
选择 Queries 选项卡。
-
在 Queries (查询) 窗格中,粘贴以下更改:
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 } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
现在,让我们查询表,返回作者为 Nadia
的所有文章。
-
在Queries (查询) 窗格中粘贴以下查询:
query allPostsByAuthor { allPostsByAuthor(author: "Nadia") { posts { id title } nextToken } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
作者为
Nadia
的全部文章应出现在查询窗格右侧的结果窗格中。如下所示:{ "data": { "allPostsByAuthor": { "posts": [ { "id": "10", "title": "The cutest dog in the world" }, { "id": "11", "title": "Did you know...?" } ], "nextToken": null } } }
Query
的分页方式与 Scan
相同。例如,如果我们查找作者为 AUTHORNAME
的所有文章,每次显示 5 个结果。
-
在Queries (查询) 窗格中粘贴以下查询:
query allPostsByAuthor { allPostsByAuthor( author: "AUTHORNAME" count: 5 ) { posts { id title } nextToken } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
作者为
AUTHORNAME
的全部文章应出现在查询窗格右侧的结果窗格中。如下所示:{ "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==" } } }
-
用上次查询返回的值更新
nextToken
参数,如下所示:query allPostsByAuthor { allPostsByAuthor( author: "AUTHORNAME" count: 5 nextToken: "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnSExqRnVhVUR3ZUhEZ2QzNGJ2QlFuY0FBQUNqekNDQW9zR0NTcUdTSWIzRFFFSEJxQ0NBbnd3Z2dKNEFnRUFNSUlDY1FZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF5Qkg4Yk1obW9LVEFTZHM3SUNBUkNBZ2dKQ3dISzZKNlJuN3pyYUVKY1pWNWxhSkNtZW1KZ0F5N1dhZkc2UEdTNHpNQzJycTkwZHFJTFV6Z25wck9Gd3pMS3VOQ2JvUXc3VDI5eCtnVExIbGg4S3BqbzB1YjZHQ3FwcDhvNDVmMG9JbDlmdS9JdjNXcFNNSXFKTXZ1MEVGVWs1VzJQaW5jZGlUaVRtZFdYWlU1bkV2NkgyRFBRQWZYYlNnSmlHSHFLbmJZTUZZM0FTdmRIL0hQaVZBb1RCMk1YZkg0eGJOVTdEbjZtRFNhb2QwbzdHZHJEWDNtODQ1UXBQUVNyUFhHemY0WDkyajhIdlBCSWE4Smcrb0RxbHozUVQ5N2FXUXdYWWU2S0h4emI1ejRITXdEdXEyRDRkYzhoMi9CbW10MzRMelVGUVIyaExSZGRaZ0xkdzF5cHJZdFZwY3dEc1d4UURBTzdOcjV2ZEp4VVR2TVhmODBRSnp1REhXREpTVlJLdDJwWmlpaXhXeGRwRmNod1BzQ3d2aVBqMGwrcWFFWU1jMXNQbENkVkFGem43VXJrSThWbS8wWHlwR2xZb3BSL2FkV0xVekgrbGMrYno1ZEM2SnVLVXdtY1EyRXlZeDZiS0Izbi9YdUViWGdFeU5PMWZTdE1rRlhyWmpvMVpzdlYyUFRjMzMrdEs0ZDhkNkZrdjh5VVR6WHhJRkxIaVNsOUx6VVdtT3BCaWhrTFBCT09jcXkyOHh1UmkzOEM3UFRqMmN6c3RkOUo1VUY0azBJdUdEbVZzM2xjdWg1SEJjYThIeXM2aEpvOG1HbFpMNWN6R2s5bi8vRE1EbDY3RlJraG5QNFNhSDBpZGI5VFEvMERLeFRBTUdhcWpPaEl5ekVqd2ZDQVJleFdlbldyOGlPVkhScDhGM25WZVdvbFRGK002N0xpdi9XNGJXdDk0VEg3b0laUU5lYmZYKzVOKy9Td25Hb1dyMTlWK0pEb2lIRVFLZ1cwMWVuYjZKUXo5Slh2Tm95ZzF3RnJPVmxGc2xwNlRHa1BlN2Rnd2IrWT0ifQ==" ) { posts { id title } nextToken } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
作者为
AUTHORNAME
的剩余文章应出现在查询窗格右侧的结果窗格中。如下所示:{ "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 } } }
使用集
到目前为止,Post
类型一直是平面的键/值对象。您还可以使用Amazon AppSyncDynamo数据库解析器对复杂的对象进行建模,例如集合、列表和地图。
让我们更新 Post
类型,加入标签。帖子可以有 0 个或更多标签,这些标签作为字符串集存储在 DynamoDB 中。您还将设置一些更改,用于添加并删除标签;还要用一个新查询扫描具有特定标签的文章。
-
选择 Schema (架构) 选项卡。
-
在 Schema (架构) 窗格中修改
Post
类型,添加新的tags
字段,如下所示:type Post { id: ID! author: String title: String content: String url: String ups: Int! downs: Int! version: Int! tags: [String!] }
-
在 Schema (架构) 窗格中修改
Query
类型,添加新的allPostsByTag
查询,如下所示: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 }
-
在 Schema (架构) 窗格中修改
Mutation
类型,添加新的addTag
和removeTag
更改,如下所示: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! }
-
选择 Save(保存)。
-
在右侧的数据类型窗格中,找到查询类型上新创建的allPostsBy标签字段,然后选择附加。
-
在数据源名称中,选择 PostDynamodbTable。
-
在 Configure the request mapping template (配置请求映射模板) 中,粘贴以下内容:
{ "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 }
-
在 Configure the response mapping template (配置响应映射模板) 中,粘贴以下内容:
{ "posts": $utils.toJson($context.result.items) #if( ${context.result.nextToken} ) ,"nextToken": $util.toJson($context.result.nextToken) #end }
-
选择 Save(保存)。
-
在右侧的 “数据类型” 窗格中,在 “突变” 类型上找到新创建的 addTag 字段,然后选择 “附加”。
-
在数据源名称中,选择 PostDynamodbTable。
-
在 Configure the request mapping template (配置请求映射模板) 中,粘贴以下内容:
{ "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 } } } }
-
在 Configure the response mapping template (配置响应映射模板) 中,粘贴以下内容:
$utils.toJson($context.result)
-
选择 Save(保存)。
-
在右侧的 “数据类型” 窗格中,在 “突变” 类型上找到新创建的 RemoveTag 字段,然后选择 “附加”。
-
在数据源名称中,选择 PostDynamodbTable。
-
在 Configure the request mapping template (配置请求映射模板) 中,粘贴以下内容:
{ "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 } } } }
-
在 Configure the response mapping template (配置响应映射模板) 中,粘贴以下内容:
$utils.toJson($context.result)
-
选择 Save(保存)。
调用 API 以处理标签
现在,您已经设置了解析器,Amazon AppSync 知道如何将传入的addTag
removeTag
、和allPostsByTag
请求转换为 DynamoDBUpdateItem
和Scan
操作。
我们选择您之前创建的一个文章进行尝试。例如,我们使用作者为 Nadia
的一篇文章。
-
选择 Queries 选项卡。
-
在Queries (查询) 窗格中粘贴以下查询:
query allPostsByAuthor { allPostsByAuthor( author: "Nadia" ) { posts { id title } nextToken } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
Nadia 的全部文章应出现在查询窗格右侧的结果窗格中。如下所示:
{ "data": { "allPostsByAuthor": { "posts": [ { "id": "10", "title": "The cutest dog in the world" }, { "id": "11", "title": "Did you known...?" } ], "nextToken": null } } }
-
让我们使用标题为
"The cutest dog in the world"
的文章。记下其id
,因为您稍后将用到它。
现在,让我们尝试添加 dog
标签。
-
在 Queries (查询) 窗格中,粘贴以下更改。您还需要更新
id
参数,改为您之前记下的值。mutation addTag { addTag(id:10 tag: "dog") { id title tags } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
文章已更新,添加了这个新标签。
{ "data": { "addTag": { "id": "10", "title": "The cutest dog in the world", "tags": [ "dog" ] } } }
您可以添加更多标签,如下所示:
-
更新更改,将
tag
参数改为puppy
。mutation addTag { addTag(id:10 tag: "puppy") { id title tags } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
文章已更新,添加了这个新标签。
{ "data": { "addTag": { "id": "10", "title": "The cutest dog in the world", "tags": [ "dog", "puppy" ] } } }
您也可以删除标签:
-
在 Queries (查询) 窗格中,粘贴以下更改。您还需要更新
id
参数,改为您之前记下的值。mutation removeTag { removeTag(id:10 tag: "puppy") { id title tags } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
文章已更新,
puppy
标签已删除。{ "data": { "addTag": { "id": "10", "title": "The cutest dog in the world", "tags": [ "dog" ] } } }
您也可以搜索具有某一标签的所有文章:
-
在Queries (查询) 窗格中粘贴以下查询:
query allPostsByTag { allPostsByTag(tag: "dog") { posts { id title tags } nextToken } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
将返回具有
dog
标签的所有文章,如下所示:{ "data": { "allPostsByTag": { "posts": [ { "id": "10", "title": "The cutest dog in the world", "tags": [ "dog", "puppy" ] } ], "nextToken": null } } }
使用列表和映射
除了使用 DynamoDB 集合外,您还可以使用 DynamoDB 列表和地图对单个对象中的复杂数据进行建模。
我们可以为文章添加评论功能。这将建模为 DynamoDB 中该Post
对象的地图对象列表。
注意:在真正的应用程序中,您会在评论自身的表中对评论进行建模。在本教程中,您仅将评论添加到 Post
表。
-
选择 Schema (架构) 选项卡。
-
在 Schema (架构) 窗格中,添加新的
Comment
类型,如下所示:type Comment { author: String! comment: String! }
-
在 Schema (架构) 窗格中修改
Post
类型,添加新的comments
字段,如下所示:type Post { id: ID! author: String title: String content: String url: String ups: Int! downs: Int! version: Int! tags: [String!] comments: [Comment!] }
-
在 Schema (架构) 窗格中修改
Mutation
类型,添加新的addComment
更改,如下所示: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! }
-
选择 Save(保存)。
-
在右侧的数据类型窗格中,找到突变类型上新创建的 addComment Com ment 字段,然后选择 AddComment 字段。
-
在数据源名称中,选择 PostDynamodbTable。
-
在 Configure the request mapping template (配置请求映射模板) 中,粘贴以下内容:
{ "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) } } }
此更新表达式将一个列表(包含新评论)追加到现有的
comments
列表中。如果这个列表不存在,将创建它。 -
在 Configure the response mapping template (配置响应映射模板) 中,粘贴以下内容:
$utils.toJson($context.result)
-
选择 Save(保存)。
调用 API 以添加评论
现在您已经设置了解析器,Amazon AppSync 知道如何将传入的addComment
请求转换为 DynamoDBUpdateItem
操作。
让我们尝试在您已添加标签的文章中添加评论。
-
选择 Queries 选项卡。
-
在Queries (查询) 窗格中粘贴以下查询:
mutation addComment { addComment( id:10 author: "Steve" comment: "Such a cute dog." ) { id comments { author comment } } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
Nadia 的全部文章应出现在查询窗格右侧的结果窗格中。如下所示:
{ "data": { "addComment": { "id": "10", "comments": [ { "author": "Steve", "comment": "Such a cute dog." } ] } } }
如果您多次执行该请求,列表中将追加多条评论。
结论
在本教程中,您构建了一个 API,允许我们使用Amazon AppSync GraphQL 在 DynamoDB 中操作 Post 对象。有关更多信息,请参阅解析程序映射模板参考。
要进行清理,可以从控制台中删除 AppSync GraphQL API。
要删除 DynamoDB 表和您为本教程创建的 IAM 角色,您可以运行以下命令来删除AWSAppSyncTutorialForAmazonDynamoDB
堆栈,或者访问Amazon CloudFormation控制台并删除堆栈:
aws cloudformation delete-stack \ --stack-name AWSAppSyncTutorialForAmazonDynamoDB