本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
使用 DynamoDB 解析器创建简单的后期应用程序
注意
我们现在主要支持 APPSYNC _JS 运行时及其文档。请考虑在此处使用 APPSYNC _JS 运行时及其指南。
本教程展示了如何将自己的 Amazon DynamoDB 表带到 GraphQL 并将其连接到 AWS AppSync GraphQL。API
您可以让代表您 AWS AppSync 配置 DynamoDB 资源。如果您愿意,也可以创建数据来源和解析器,将现有的表连接到 GraphQL 架构。在这两种情况下,您都可以通过 GraphQL 语句读写您的 DynamoDB 数据库,并订阅实时数据。
要将 GraphQL 语句转换为 DynamoDB 操作,并将响应转换回 GraphQL,需要完成一些特定的配置步骤。本教程通过一些现实世界的场景和数据访问模式介绍了配置过程。
设置您的 DynamoDB 表
要开始本教程,首先需要按照以下步骤配置 AWS 资源。
-
使用以下 AWS CloudFormation 模板置备 AWS 资源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
或者,您可以在自己的 AWS 账户中在美国西部 2(俄勒冈)地区启动以下 AWS CloudFormation 堆栈。
这会创建以下内容:
-
名为
AppSyncTutorial-Post
的 DynamoDB 表,用于保留Post
数据。 -
允许 AWS AppSync 与
Post
表交互的IAM角色和关联的IAM托管策略。
-
-
要查看有关堆栈和已创建资源的更多详细信息,请运行以下CLI命令:
aws cloudformation describe-stacks --stack-name AWSAppSyncTutorialForAmazonDynamoDB
-
稍后要删除资源,您可以运行以下操作:
aws cloudformation delete-stack --stack-name AWSAppSyncTutorialForAmazonDynamoDB
创建你的 GraphQL API
要在下面创建 GraphQLAPI,请执行以下操作: AWS AppSync
-
登录 AWS Management Console 并打开AppSync 控制台
。 -
在APIs仪表板中,选择创建API。
-
-
在 “自定义您的” API 或 “从亚马逊 DynamoDB 导入” 窗口下,选择从头开始构建。
-
选择同一窗口右侧的开始。
-
-
在API名称字段中,将的名称设置API为
AWSAppSyncTutorial
。 -
选择创建。
AWS AppSync 控制台使用API密钥身份验证模式API为您创建一个新的 GraphQL。您可以使用控制台设置 GraphQL 的其余部分,API并在本教程的其余部分中对其运行查询。
定义基本帖子 API
现在,您已经创建了 AWS AppSync GraphQLAPI,可以设置一个基本架构,允许基本创建、检索和删除帖子数据。
-
登录 AWS Management Console 并打开AppSync 控制台
。 -
在APIs仪表板中,选择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! }
-
-
选择保存。
此架构定义 Post
类型,执行操作以添加并获取 Post
对象。
为 DynamoDB 表配置数据来源
接下来,将架构中定义的查询和变更链接到 AppSyncTutorial-Post
DynamoDB 表。
首先, AWS AppSync 需要注意你的表格。您可以通过在以下位置设置数据源来实现此目的 AWS AppSync:
-
登录 AWS Management Console 并打开AppSync 控制台
。 -
在APIs控制面板中,选择您的 GraphQL API。
-
在侧边栏中,选择数据来源。
-
-
选择创建数据来源。
-
对于数据来源名称,输入
PostDynamoDBTable
。 -
对于数据来源类型,选择 Amazon DynamoDB 表。
-
对于区域,请选择美国-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:*" ] } ] }
-
-
选择创建。
设置 addPost 解析器 (DynamoD PutItem B)
在知道 DynamoDB 表之后 AWS AppSync ,您可以通过定义解析器将其链接到各个查询和变更。您创建的第一个解析器是 addPost
解析器,可用于在 AppSyncTutorial-Post
DynamoDB 表中创建文章。
解析器具有以下组件:
-
GraphQL 架构中的位置,用于附加解析器。在本例中,您将设置
addPost
类型的Mutation
字段的解析器。在调用方调用mutation { addPost(...){...} }
时,将调用该解析器。 -
此解析器所用的数据来源。在本例中,您要使用之前定义的
PostDynamoDBTable
数据来源,这样您就可以在AppSyncTutorial-Post
DynamoDB 表中添加条目。 -
请求映射模板。请求映射模板的目的是接收来自调用者的传入请求,并将其转换为要对 DynamoDB 执行的 AWS AppSync 指令。
-
响应映射模板。响应映射模板的任务是将 DynamoDB 的响应转换回 GraphQL 期待获得的内容。如果 DynamoDB 中的数据形态与 GraphQL 中的
Post
类型不同,此模板很有用。但在此例中它们的形态相同,所以只用于传递数据。
设置解析器:
-
登录 AWS Management Console 并打开AppSync 控制台
。 -
在APIs控制面板中,选择您的 GraphQL API。
-
在侧边栏中,选择数据来源。
-
-
选择创建数据来源。
-
对于数据来源名称,输入
PostDynamoDBTable
。 -
对于数据来源类型,选择 Amazon DynamoDB 表。
-
对于区域,请选择美国-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:*" ] } ] }
-
-
选择创建。
-
选择架构选项卡。
-
在右侧的 “数据类型” 窗格中,找到 “突变” 类型上的addPost字段,然后选择 “附加”。
-
在 “操作” 菜单中,选择 “更新运行时”,然后选择 “设备解析器”(VTL仅限)。
-
在 Data source name (数据源名称) 中,选择 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
部分向 DynamoDB 表示该值将是一个字符串值。 AWS AppSync 实际的值由author
参数填充。与此类似,version
字段是一个数字字段,因为它使用N
作为类型。最后,您还将初始化ups
、downs
和version
字段。在本教程中,您已指定 GraphQL
ID!
类型(用于索引插入到 DynamoDB 的新项目)作为客户端参数的一部分。 AWS AppSync 附带了一个名为的自动生成身份的实用程序$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
类型的形态完全匹配,响应映射模板只会直接传递结果。还请注意,此教程中的所有示例均使用同一响应映射模板,所以您只需创建一个文件。 -
选择保存。
致电API添加帖子
现在,解析器已设置完毕, AWS 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 } } }
以下是具体过程:
-
AWS AppSync 收到了
addPost
变异请求。 -
AWS 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 } } }
-
AWS AppSync 使用请求映射文档生成并执行 DynamoDB
PutItem
请求。 -
AWS 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 解析器 (DynamoD GetItem B)
您现在能够将数据添加到 AppSyncTutorial-Post
DynamoDB 表中,您需要设置 getPost
查询,以使其可以从 AppSyncTutorial-Post
表中检索该数据。为了实现此目的,您要设置另一解析器。
-
选择架构选项卡。
-
在右侧的数据类型窗格中,找到查询类型上的getPost字段,然后选择附加。
-
在 “操作” 菜单中,选择 “更新运行时”,然后选择 “设备解析器”(VTL仅限)。
-
在 Data source name (数据源名称) 中,选择 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)
-
选择保存。
致电API获取帖子
现在,解析器已经设置完毕, AWS AppSync 知道如何将传入的getPost
查询转换为 DynamoDB GetItem
操作。现在,您可以运行查询,检索之前创建的文章。
-
选择 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 } } }
以下是具体过程:
-
AWS AppSync 收到了
getPost
查询请求。 -
AWS AppSync 接受了请求和请求映射模板,并生成了请求映射文档。如下所示:
{ "version" : "2017-02-28", "operation" : "GetItem", "key" : { "id" : { "S" : "123" } } }
-
AWS AppSync 使用请求映射文档生成并执行 DynamoDB GetItem 请求。
-
AWS 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 传输到 AWS AppSync。例如,请求映射模板可能类似于以下代码片段:
{ "version" : "2017-02-28", "operation" : "GetItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id) }, "projection" : { "expression" : "#author, id, title", "expressionNames" : { "#author" : "author"} } }
创建 updatePost 突变 (DynamoD UpdateItem B)
到目前为止,您可以在 DynamoDB 中创建和检索 Post
对象。现在,您要设置一项新的变更,以便更新对象。您将使用 UpdateItem DynamoDB 操作来执行此操作。
-
选择架构选项卡。
-
在 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! }
-
选择保存。
-
在右侧的 “数据类型” 窗格中,在 “突变” 类型上找到新创建的updatePost字段,然后选择 “附加”。
-
在 “操作” 菜单中,选择 “更新运行时”,然后选择 “设备解析器”(VTL仅限)。
-
在 Data source name (数据源名称) 中,选择 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 } } } }
注意:此解析器使用的是 D UpdateItem ynamoDB,这与操作有很大不同。 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致电更新帖子
现在解析器已经设置好了, AWS AppSync 知道如何将传入的update
突变转换为 DynamoDB 操作。Update
现在,您可以运行变更,以更新您之前写入的项目。
-
选择 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
字段,因为请求映射模板没有要求 AWS AppSync 和 DynamoDB 对这些字段执行任何操作。此外,该version
字段增加了 1,因为您要求 AWS AppSync 和 DynamoDB 向该字段添加 1。version
修改 updatePost 解析器 (DynamoDB UpdateItem)
updatePost
变更看上去不错,但它有两个主要问题:
-
如果您只希望更新一个字段,则必须更新所有字段。
-
如果两个人同时修改对象,您可能会丢失信息。
为了解决这些问题,您要修改 updatePost
变更,做到只修改请求中指定的参数,然后在 UpdateItem
操作中添加条件。
-
选择架构选项卡。
-
在 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! }
-
选择保存。
-
在右侧的 “数据类型” 窗格中,找到 “突变类型” 上的updatePost字段。
-
选择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) } } }
-
选择保存。
此模板是一个更复杂的示例。它演示了映射模板的强大功能和灵活性。它遍历所有参数,跳过 id
和 expectedVersion
。如果参数设置为某个值,它会要求 AWS AppSync 和 DynamoDB 在 DynamoDB 中更新该对象上的该属性。如果该属性设置为空,它会要求 AWS AppSync 和 DynamoDB 从帖子对象中移除该属性。如果未指定参数,该属性会保留原样。它还会递增 version
字段。
还有一个新的 condition
部分。条件表达式允许您根据执行 AWS AppSync 操作之前已在 DynamoDB 中的对象的状态告知和 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 } } }
在此请求中,您要求 AWS 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
参数匹配。请求成功,这意味着 DynamoDB 中的version
字段已增加到3
。 -
第二次运行请求时,DynamoDB 中的文章的
version
字段的值为3
,它与expectedVersion
参数不匹配。
这种模式通常被称为乐观锁。
AWS AppSync DynamoDB 解析器的一个特点是它返回 DynamoDB 中帖子对象的当前值。您可以在 GraphQL 响应的 data
部分的 errors
字段中找到这个值。您的应用程序可以利用此信息决定应如何继续。在该示例中,您可以看到 DynamoDB 中的对象的 version
字段设置为 3
,因此,您只需将 expectedVersion
参数更新为 3
,请求就会再次成功。
有关如何处理条件检查失败的更多信息,请参阅条件表达式映射模板参考文档。
创建 upvotePost 和 downvotePost 突变 (DynamoDB UpdateItem)
该Post
类型有ups
和downs
字段可以记录赞成票和反对票,但到目前为止,它们API不允许我们对它们做任何事情。让我们添加一些变更,对文章点赞和差评。
-
选择架构选项卡。
-
在 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! }
-
选择保存。
-
在右侧的 “数据类型” 窗格中,在 “突变” 类型上找到新创建的upvotePost字段,然后选择 “附加”。
-
在 “操作” 菜单中,选择 “更新运行时”,然后选择 “设备解析器”(VTL仅限)。
-
在 Data source name (数据源名称) 中,选择 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)
-
选择保存。
-
在右侧的数据类型窗格中,找到 Mutation 类型上的新创建的
downvotePost
字段,然后选择附加。 -
在 Data source name (数据源名称) 中,选择 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)
-
选择保存。
致电 the API 对帖子投赞成票和反对票
现在,新的解析器已经设置完毕, AWS 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解析器 (DynamoD DeleteItem B)
接下来您要设置的变更是删除一个文章。您将使用 DeleteItem
DynamoDB 操作完成该操作。
-
选择架构选项卡。
-
在 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
字段设为可选,稍后在添加请求映射模板时将对此进行说明。 -
选择保存。
-
在右侧的数据类型窗格中,找到 Mutation 类型上的新创建的 delete 字段,然后选择附加。
-
在 “操作” 菜单中,选择 “更新运行时”,然后选择 “设备解析器”(VTL仅限)。
-
在 Data source name (数据源名称) 中,选择 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
属性与expectedVersion
完全匹配时,才允许DeleteItem
请求成功。如果未设置此参数,则DeleteItem
请求中不指定条件表达式。无论version
值如何,或者项目在 DynamoDB 中是否存在,该请求都会成功。 -
在 Configure the response mapping template (配置响应映射模板) 中,粘贴以下内容:
$utils.toJson($context.result)
注意:即使您要删除一个项目,如果该项目不是已经删除,还是可以返回要删除的项目。
-
选择保存。
有关DeleteItem
请求映射的更多信息,请参阅DeleteItem参考文档。
致电API删除帖子
现在解析器已经设置好了, AWS AppSync 知道如何将传入的delete
突变转换为 DynamoDB 操作。DeleteItem
现在,您可以运行变更,从表中删除一些内容。
-
选择 Queries 选项卡。
-
在 Queries (查询) 窗格中,粘贴以下更改。您还需要将
id
参数更新为您以前记下的值。mutation deletePost { deletePost(id:123) { id author title content url ups downs version } }
-
选择 Execute query (执行查询)(橙色播放按钮)。
-
该文章已从 DynamoDB 中删除。请注意, AWS 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 中的文章的
version
值与参数中指定的expectedValue
不匹配。对象的当前值返回到 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 扫描)
到目前为止,API只有当你知道要查看id
的每篇文章时,才有用。让我们添加新的解析器,它可以返回表中的所有文章。
-
选择架构选项卡。
-
在 Schema (架构) 窗格中修改
Query
类型,添加新的allPost
查询,如下所示:type Query { allPost(count: Int, nextToken: String): PaginatedPosts! getPost(id: ID): Post }
-
添加新
PaginationPosts
类型:type PaginatedPosts { posts: [Post!]! nextToken: String }
-
选择保存。
-
在右侧的数据类型窗格中,在查询类型上找到新创建的allPost字段,然后选择附加。
-
在 “操作” 菜单中,选择 “更新运行时”,然后选择 “设备解析器”(VTL仅限)。
-
在 Data source name (数据源名称) 中,选择 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
,其中包含一组文章和一个分页标记。此对象的形状与 D AWS AppSync ynamoDB 解析器返回的形状不同:帖子列表在 DynamoDB 解析器结果items
中被调用,但会被调用。 AWS AppSyncposts
PaginatedPosts
-
选择保存。
有关 Scan
请求映射的更多信息,请参阅 Scan 参考文档。
致电扫描所有帖子 API
现在,解析器已经设置完毕, AWS AppSync 知道如何将传入的allPost
查询转换为 DynamoDB Scan
操作。现在您可以扫描整个表,检索所有文章。
在进行尝试之前,您需要在表中填充一些数据,因为您已经删除了之前使用的所有内容。
-
选择 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 表已具有一个名为 author-index
的 GlobalSecondaryIndex
,您可以将其与 DynamoDB Query
操作一起使用以检索特定作者创建的所有文章。
-
选择架构选项卡。
-
在 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
类型。 -
选择保存。
-
在右侧的 “数据类型” 窗格中,在 “查询” 类型上找到新创建的 “allPostsBy作者” 字段,然后选择 “附加”。
-
在 “操作” 菜单中,选择 “更新运行时”,然后选择 “设备解析器”(VTL仅限)。
-
在 Data source name (数据源名称) 中,选择 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
解析器中所用的相同。 -
选择保存。
了解有关 Query
请求映射的更多信息,请参阅 Query 参考文档。
API致电查询作者的所有帖子
现在解析器已经设置好了, AWS AppSync 知道如何将传入的allPostsByAuthor
突变转换为针对索引的 DynamoDB 操作Query
。author-index
现在,您可以查询表,检索某一作者的所有文章。
但首先我们需要在表中再填充一些文章,因为目前所有文章都是同一作者。
-
选择 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
类型一直是平面键/值对象。您还可以使用 AWS AppSyncDynamo数据库解析器对复杂的对象进行建模,例如集合、列表和地图。
让我们更新 Post
类型,加入标签。一篇文章可以具有 0 个或更多标签,这些标签作为字符串集存储在 DynamoDB 中。您还将设置一些变更,用于添加并删除标签;还要用一个新查询扫描具有特定标签的文章。
-
选择架构选项卡。
-
在 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! }
-
选择保存。
-
在右侧的数据类型窗格中,在查询类型上找到新创建的allPostsBy标签字段,然后选择附加。
-
在 Data source name (数据源名称) 中,选择 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 }
-
选择保存。
-
在右侧的 “数据类型” 窗格中,在 “突变” 类型上找到新创建的addTag字段,然后选择 “附加”。
-
在 Data source name (数据源名称) 中,选择 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)
-
选择保存。
-
在右侧的 “数据类型” 窗格中,在 “突变” 类型上找到新创建的removeTag字段,然后选择 “附加”。
-
在 Data source name (数据源名称) 中,选择 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)
-
选择保存。
致电API使用 Tags
现在您已经设置了解析器, AWS AppSync 知道如何将传入的addTag
removeTag
、和allPostsByTag
请求转换为 D UpdateItem
ynamo Scan
DB 和操作。
我们选择您之前创建的一个文章进行尝试。例如,我们使用作者为 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 (架构) 窗格中,添加新的
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! }
-
选择保存。
-
在右侧的 “数据类型” 窗格中,在 “突变” 类型上找到新创建的addComment字段,然后选择 “附加”。
-
在 Data source name (数据源名称) 中,选择 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)
-
选择保存。
致电API添加评论
现在您已经设置了解析器, AWS AppSync 知道如何将传入的addComment
请求转换为 DynamoDB 操作UpdateItem
。
让我们尝试在您已添加标签的文章中添加评论。
-
选择 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." } ] } } }
如果您多次执行该请求,列表中将追加多条评论。
结论
在本教程中,您构建了一个,它允许我们使用 AWS AppSync 和 API GraphQL 在 DynamoDB 中操作 Post 对象。有关更多信息,请参阅解析器映射模板参考。
要进行清理,您可以API从控制台中删除 AppSync GraphQL。
要删除 DynamoDB 表和IAM您为本教程创建的角色,您可以运行以下命令来删除AWSAppSyncTutorialForAmazonDynamoDB
堆栈,或者访问 AWS CloudFormation 控制台删除堆栈:
aws cloudformation delete-stack \ --stack-name AWSAppSyncTutorialForAmazonDynamoDB