教程:DynamoDB 解析程序程序 - Amazon AppSync
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 Amazon Web Services 服务入门

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

教程:DynamoDB 解析程序程序

本教程展示了如何在中使用您自己的 Amazon DynamoDB 表。AmazonAppSync 并将它们连接到 GraphQL API。

你可以让AmazonAppSync 代表您预配置 DynamoDB 资源。如果您愿意,也可以创建数据源和解析程序,将现有的表连接到 GraphQL 架构。在这两种情况下,您都可以通过 GraphQL 语句读写您的 DynamoDB 数据库,并订阅实时数据。

要将 GraphQL 语句转换为 DynamoDB 操作,并将响应转换回 GraphQL,需要完成一些特定的配置步骤。本教程通过一些现实世界的场景和数据访问模式介绍了配置过程。

设置 DynamoDB 表

要开始此教程,需要首先预配置Amazon使用以下内容的资源Amazon CloudFormation模板:

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 CloudFormation在您的美国西部 2(俄勒冈)区域堆叠Amazonaccount.

这会创建以下内容:

  • 名为 DynamoDB 表AppSyncTutorial-Post那将保持Post数据。

  • 一个 IAM 角色和关联的 IAM 托管策略,允许AmazonAppSync 与Post表。

要了解堆栈和所创建资源的更多详细信息,请运行以下 CLI 命令:

aws cloudformation describe-stacks \ --stack-name AWSAppSyncTutorialForAmazonDynamoDB

稍后要删除资源,您可以运行以下操作:

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

创建您的 GraphQL API

要在中创建 GraphQL APIAmazonAppSync:

  • 打开AmazonAppSync 控制台然后选择创建 API.

  • 将 API 的名称设置为 AWSAppSyncTutorial

  • 选择自定义架构

  • 选择 Create (创建)

这些区域有:AmazonAppSync 控制台会使用 API 密钥身份验证模式为您创建新的 GraphQL API。您可以根据本教程后面的说明,使用控制台设置 GraphQL API 的其余部分,并针对它运行查询。

定义基本的 Post API

现在你设置了AmazonAppSync GraphQL API,您可以设置基本架构,允许对文章数据进行基本的创建、检索和删除操作。

在AmazonAppSync 控制台,选择架构选项卡。在 Schema (架构) 窗格中,将内容替换为以下代码,然后选择 Save (保存)

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-PostDynamoDB 表。

首先,AmazonAppSync 需要知道您的表。要实现此目的,需要在中设置数据源。AmazonAppSync:

  • 选择 Data source (数据源) 选项卡。

  • 选择 New (新建) 创建新的数据源。

  • 对于数据源名称,输入 PostDynamoDBTable

  • 对于数据源类型,选择 Amazon DynamoDB table (Amazon DynamoDB 表)

  • 对于区域,选择 US-WEST-2

  • 在表的列表中,选择AppSyncPost 教程DynamoDB 表。

  • 创建或使用现有角色部分,选择现有角色.

  • 选择 Create (创建)

设置 addPost 解析程序 (DynamoDB PutItem)

晚于AmazonAppSync 知道有 DynamoDB 表,您可以定义与单个查询和更改链接。解析程序. 你创建的第一个解析器是addPost解析程序,您可以在中创建一个文章。AppSyncTutorial-PostDynamoDB 表。

解析程序具有以下组件:

  • GraphQL 架构中的位置,用于附加解析程序。在本例中,您将设置 addPost 类型的 Mutation 字段的解析程序。调用者调用 mutation { addPost(...){...} } 时,将调用此解析程序。

  • 此解析程序所用的数据源。在本例中,您要使用之前定义的 PostDynamoDBTable 数据源,这样您就可以在 AppSyncTutorial-Post DynamoDB 表中添加条目。

  • 请求映射模板。请求映射模板的目的是将调用者的传入请求转换为指令:AmazonAppSync 对 DynamoDB 执行。

  • 响应映射模板。响应映射模板的任务是将 DynamoDB 的响应转换回 GraphQL 期待获得的内容。如果 DynamoDB 中的数据形态与 GraphQL 中的 Post 类型不同,此模板很有用。但在此例中它们的形态相同,所以只用于传递数据。

设置解析程序:

  • 选择 Schema (架构) 选项卡。

  • 数据类型在右侧的窗格中,找到AddPost字段中更改键入,然后选择。Attach.

  • 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 } } }

    注意:Atype在所有键和属性值中指定。例如,您将 author 字段设置为 { "S" : "${context.arguments.author}" }。这些区域有:S部分指示AmazonAppSync 和 DynamoDB,此值为字符串。实际的值由 author 参数填充。与此类似,version 字段是一个数字字段,因为它使用 N 作为类型。最后,您还将初始化 upsdownsversion 字段。

    在本教程中,您已指定 GraphQLID!类型,它作为客户端参数的一部分,会为插入 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表格完全匹配Post输入 GraphQL,响应映射模板只会直接传递结果。还请注意,此教程中的所有示例均使用同一响应映射模板,所以您只需创建一个文件。

  • 选择 Save (保存)

调用 API 来添加文章

现在解析程序已设置完成,AmazonAppSync 可以翻译传入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 } } }

以下是具体过程:

  • AmazonAppSync 收到addPost更改请求。

  • AmazonAppSync 利用请求和请求映射模板,生成请求映射文档。如下所示:

    { "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 } } }
  • AmazonAppSync 使用请求映射文档生成并执行 DynamoDBPutItem请求.

  • AmazonAppSync 获取了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-PostDynamoDB 表,您需要设置getPost查询以便它可以从AppSyncTutorial-Post表。为了实现此目的,您要设置另一解析程序。

  • 选择 Schema (架构) 选项卡。

  • 数据类型在右侧的窗格中,找到getPost字段中查询键入,然后选择。Attach.

  • 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)
  • 选择 Save (保存)

调用 API 以获取文章

现在解析器已经设置好了,AmazonAppSync 知道如何翻译来电getPost查询 DynamoDBGetItemoperation. 现在,您可以运行查询,检索之前创建的文章。

  • 选择 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 } } }

以下是具体过程:

  • AmazonAppSync 收到getPost查询请求。

  • AmazonAppSync 利用请求和请求映射模板,生成请求映射文档。如下所示:

    { "version" : "2017-02-28", "operation" : "GetItem", "key" : { "id" : { "S" : "123" } } }
  • AmazonAppSync 使用请求映射文档生成并执行 DynamoDB GetItem 请求。

  • AmazonAppSync 获取了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 }
  • 通过响应映射文档进行传递,没有变化。

  • 在响应中返回检索到的对象。

创建 updatePost 更改 (DynamoDB UpdateItem)

到目前为止,您可以创建和检索PostDynamoDB 中的对象。现在,您要设置一项新的更改,以便更新对象。您将使用 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 (保存)

  • 数据类型在右侧的窗格中,找到新创建的updatePost字段中更改键入然后选择Attach.

  • 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 } } } }

    注意:此解析程序使用的是 DynamoDB UpdateItem,它与 PutItem 操作截然不同。您只要求 DynamoDB 更新某些属性,而不会写入整个项目。这是使用 DynamoDB 更新表达式实现的。表达式本身是在 expression 部分的 update 字段中指定的。它会设置 authortitlecontent 和 URL 属性,还会递增 version 字段。要使用的值不会出现在表达式本身;表达式中的占位符名称以冒号打头,并在 expressionValues 字段中进行定义。最后,DynamoDB 还有一些保留关键字是不能出现在中的。expression. 例如,url 是保留关键字,所以要更新 url 字段,您可使用名称占位符,并在 expressionNames 字段中定义它们。

    有关 UpdateItem 请求映射的更多信息,请参阅 UpdateItem 参考文档。有关如何编写更新表达式的更多信息,请参阅 DynamoDB UpdateExpressions 文档

  • Configure the response mapping template (配置响应映射模板) 中,粘贴以下内容:

    $utils.toJson($context.result)

调用 API 以更新文章

现在解析器已经设置好了,AmazonAppSync 知道如何翻译来电updateDynamoDB 的突变Updateoperation. 现在,您可以运行更改,以更新您之前写入的项目。

  • 选择 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 } } }

在此示例中,upsdowns没有修改字段,因为请求映射模板没有要求AmazonAppSync 和 DynamoDB 可以对这些字段执行任何操作。另外,version因为您要求,字段增加了 1AmazonAppSync 和 DynamoDB 将 1 添加到version字段中返回的子位置类型。

修改 updatePost 解析程序 (DynamoDB UpdateItem)

updatePost 更改看上去不错,但它有两个主要问题:

  • 如果您只希望更新一个字段,则必须更新所有字段。

  • 如果两个人同时修改对象,您可能会丢失信息。

为了解决这些问题,您要修改 updatePost 更改,做到只修改请求中指定的参数,然后在 UpdateItem 操作中添加条件。

  • 选择 Schema (架构) 选项卡。

  • Schema (架构) 窗格中修改 Mutation 类型中的 updatePost 字段,删除 authortitlecontenturl 参数的感叹号,确保 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 (保存)

  • 数据类型在右侧的窗格中,找到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) } } }
  • 选择 Save (保存)

此模板是一个更复杂的示例。它演示了映射模板的强大功能和灵活性。它遍历所有参数,跳过 idexpectedVersion。如果参数设置为某种东西,它会问AmazonAppSync 和 DynamoDB 以更新 DynamoDB 中对象的属性。如果属性设置为 null,它会询问Amazon利用 AppSync 和 DynamoDB,从文章对象中删除该属性。如果未指定参数,该属性会保留原样。它还会递增 version 字段。

还有一个新的 condition 部分。使用条件表达式可以告诉Amazon根 AppSync 执行操作前已在 DynamoDB 中的对象状态,请求是否应成功。在这种情况下,您只需要UpdateItem请求成功如果version当前位于 DynamoDB 中的项目的字段与expectedVersion参数。

有关条件表达式的更多信息,请参阅条件表达式参考文档。

调用 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 } } }

在此请求中,您问过AmazonAppSync 和 DynamoDB 来更新titlecontent仅限于字段。它不会处理所有其他字段(除了递增 version 字段)。您将 title 属性设为新值,并删除文章的 content 属性。authorurlupsdowns 字段没有变化。

请尝试再次执行更改请求,保持请求完全不变。您可以看到类似以下内容的响应:

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

  • 您第一次运行请求时,versionDynamoDB 中帖子的字段是2,它匹配expectedVersion参数。请求成功,意味着version在 DynamoDB 中将字段增加到3.

  • 您第二次运行请求时,versionDynamoDB 中帖子的字段是3,这与expectedVersion参数。

这种模式通常被称为乐观锁

的一个功能AmazonAppSync DynamoDB 解析程序是,它会返回 DynamoDB 中文章对象的当前值。您可以在 GraphQL 响应的 data 部分的 errors 字段中找到这个值。您的应用程序可以利用此信息决定应如何继续。在这种情况下,您可以看到versionDynamoDB 中对象的字段设置为3,所以你可以直接更新expectedVersion参数3然后请求将再次成功。

有关如何处理条件检查失败的更多信息,请参阅条件表达式映射模板参考文档。

创建 upvotePost 和 downvotePost 更改 (DynamoDB UpdateItem)

Post 类型有 upsdowns 字段,用于记录赞同投票和反对投票,但现在还无法通过 API 使用它们。让我们添加一些更改,对文章进行赞同和反对投票。

  • 选择 Schema (架构) 选项卡。

  • Schema (架构) 窗格中修改 Mutation 类型,添加新的 upvotePostdownvotePost 更改,如下所示:

    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 (保存)

  • 数据类型在右侧的窗格中,找到新创建的upvotePost字段中更改键入,然后选择。Attach.

  • 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)
  • 选择 Save (保存)

  • 数据类型在右侧的窗格中,找到新创建的downvotePost字段中更改键入,然后选择。Attach.

  • 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)
  • 选择 Save (保存)

调用 API,为文章投赞同票或反对票

现在新的解析程序已设置完成,AmazonAppSync 知道如何翻译来电upvotePost或者downvoteDynamoDB 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 } } }
  • 再选择几次 (执行查询) 按钮。您应看到,每次您执行查询时,upsversion 字段均会递增 1。

  • 更改查询以调用 downvotePost 更改,如下所示:

    mutation votePost { downvotePost(id:123) { id author title content url ups downs version } }
  • 选择 Execute query (执行查询)(橙色播放按钮)。这次您应看到,每次您执行查询时,downsversion 字段均会递增 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)

接下来您要设置的更改是删除一个文章。您要使用DeleteItemDynamoDB 操作。

  • 选择 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 (保存)

  • 数据类型在右侧的窗格中,找到新创建的delete字段中更改键入,然后选择。Attach.

  • 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请求中的参数,模板添加了一个条件,该条件只允许DeleteItem如果项目已被删除或者versionDynamoDB 中帖子的属性完全匹配expectedVersion. 如果未设置此参数,则 DeleteItem 请求中不指定条件表达式。无论其价值如何,它都会成功versionDynamoDB 中是否存在该项目。

  • Configure the response mapping template (配置响应映射模板) 中,粘贴以下内容:

    $utils.toJson($context.result)

    注意:即使您要删除一个项目,如果该项目不是已经删除,还是可以返回要删除的项目。

  • 选择 Save (保存)

有关 DeleteItem 请求映射的更多信息,请参阅 DeleteItem 参考文档。

调用 API 以删除文章

现在解析器已经设置好了,AmazonAppSync 知道如何翻译来电deleteDynamoDB 的突变DeleteItemoperation. 现在,您可以运行更改,从表中删除一些内容。

  • 选择 Queries 选项卡。

  • Queries (查询) 窗格中,粘贴以下更改。您还需要更新 id 参数,改为您之前记下的值。

    mutation deletePost { deletePost(id:123) { id author title content url ups downs version } }
  • 选择 Execute query (执行查询)(橙色播放按钮)。

  • 文章已经从 DynamoDB 中删除。请注意AmazonAppSync 返回已从 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:versionDynamoDB 中的帖子与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 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 (保存)

  • 数据类型在右侧的窗格中,找到新创建的allPost字段中查询键入,然后选择。Attach.

  • 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,其中包含一组文章和一个分页标记。此对象的形状与从AmazonAppSync DynamoDB 解析器:帖子列表称为items中的AmazonAppSync DynamoDB 解析器结果,但被称为postsPaginatedPosts.

  • 选择 Save (保存)

有关 Scan 请求映射的更多信息,请参阅 Scan 参考文档。

调用 API 以扫描所有文章

现在解析器已经设置好了,AmazonAppSync 知道如何翻译来电allPost查询 DynamoDBScanoperation. 现在您可以扫描整个表,检索所有文章。

在进行尝试之前,您需要在表中填充一些数据,因为您已经删除了之前使用的所有内容。

  • 选择 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 } } }

设置 allPostsByAuthor 解析程序 (DynamoDB 查询)

除了可以扫描 DynamoDB 中的所有文章,您还可以查询 DynamoDB,检索由特定作者创建的文章。您之前创建的 DynamoDB 表已有一个GlobalSecondaryIndex称作author-index你可以与 DynamoDB 一起使用Query操作,检索某一作者创建的所有文章。

  • 选择 Schema (架构) 选项卡。

  • Schema (架构) 窗格中修改 Query 类型,添加新的 allPostsByAuthor 查询,如下所示:

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

    注意:这使用相同的PaginatedPosts键入您与allPost查询。

  • 选择 Save (保存)

  • 数据类型在右侧的窗格中,找到新创建的allPostsByAuthor字段中查询键入,然后选择。Attach.

  • 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解析程序。

  • 选择 Save (保存)

了解有关 Query 请求映射的更多信息,请参阅 Query 参考文档。

调用 API 以查询某一作者的所有文章

现在解析器已经设置好了,AmazonAppSync 知道如何翻译来电allPostsByAuthorDynamoDB 的突变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 类型一直是平面的键/值对象。您还可以使用AmazonAppSyncDynamoDB 解析程序,例如集、列表和映射。

让我们更新 Post 类型,加入标签。一个文章可以没有标签,也可以有多个标签,它们作为字符串集存储在 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 类型,添加新的 addTagremoveTag 更改,如下所示:

    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 (保存)

  • 数据类型在右侧的窗格中,找到新创建的allPostsByTag字段中查询键入,然后选择。Attach.

  • 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 }
  • 选择 Save (保存)

  • 数据类型在右侧的窗格中,找到新创建的AddTag字段中更改键入,然后选择。Attach.

  • 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)
  • 选择 Save (保存)

  • 数据类型在右侧的窗格中,找到新创建的RremoveTag字段中更改键入,然后选择。Attach.

  • 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)
  • 选择 Save (保存)

调用 API 以处理标签

现在您已设置解析程序,AmazonAppSync 知道如何翻译来电addTagremoveTag, 和allPostsByTag请求 DynamoDBUpdateItemScan运算。

我们选择您之前创建的一个文章进行尝试。例如,我们使用作者为 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 列表和映射,在单独的对象中建模复杂的数据。

我们可以为文章添加评论功能。在中,此功能作为映射列表对象进行建模。PostDynamoDB 中的对象。

注意:在真正的应用程序中,您会在评论自身的表中对评论进行建模。在本教程中,您仅将评论添加到 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字段中更改键入,然后选择。Attach.

  • 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)
  • 选择 Save (保存)

调用 API 以添加评论

现在您已设置解析程序,AmazonAppSync 知道如何翻译来电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." } ] } } }

如果您多次执行该请求,列表中将追加多条评论。

Conclusion

在本教程中,您构建了 API,使用该 API 处理 DynamoDB 中的 Post 对象。AmazonAppSync 和 GraphQL。有关更多信息,请参阅解析程序映射模板参考

要进行清理,您可以从控制台中删除 AppSync GraphQL API。

要删除 DynamoDB 表以及您为本教程创建的 IAM 角色,您可以运行以下代码删除AWSAppSyncTutorialForAmazonDynamoDB堆叠,或者访问Amazon CloudFormation控制台并删除堆栈:

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