本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
教程:管道解析程序
AmazonAppSync 提供了一种通过单元解析程序将 GraphQL 字段连接到单个数据源的简单方法。但是,执行单个操作可能还不够。管道解析程序提供了对数据源连续执行操作的能力。在 API 中创建函数并将这些函数附加到管道解析程序。每个函数执行结果将通过管道传输到下一个函数,直到没有要执行的函数为止。利用管道解析程序,您现在可直接在中构建更复杂的工作流AmazonAppSync。在本教程中,您将构建一个简单的图片查看应用程序,用户可以在其中发布图片和查看其好友发布的图片。
一键设置
如果你想在中自动设置 GraphQL 终端节点AmazonAppSync 配置了所有解析器和必要的Amazon资源,你可以使用以下Amazon CloudFormation:模板:
此堆栈在您的账户中创建以下资源:
-
适用于的 IAM 角色AmazonAppSync 访问您账户中的资源
-
2 个 DynamoDB 表
-
1 个 Amazon Cognito 用户池
-
2 个 Amazon Cognito 用户池组
-
3 个 Amazon Cognito 用户池用户
-
1AmazonAppSync API
在最后Amazon CloudFormation对于您已创建的三个 Amazon Cognito 用户,您将分别收到一封电子邮件。每封电子邮件均包含一个临时密码,您可使用此密码以 Amazon Cognito 用户身份登录AmazonAppSync 控制台。保存密码完成本教程的剩余部分。
手动设置
如果您希望通过手动完成分步过程,请通过AmazonAppSync 控制台,请按照以下设置过程操作。
设置您的 NonAmazon AppSync资源
该 API 与两个 DynamoDB 表进行通信:a图片存储图片的表格和朋友们存储用户之间关系的表。此 API 配置为使用 Amazon Cognito 用户池作为身份验证类型。以下Amazon CloudFormation堆栈在账户中设置这些资源。
在最后Amazon CloudFormation对于您已创建的三个 Amazon Cognito 用户,您将分别收到一封电子邮件。每封电子邮件均包含一个临时密码,您可使用此密码以 Amazon Cognito 用户身份登录AmazonAppSync 控制台。保存密码完成本教程的剩余部分。
创建您的 GraphQL API
要在中创建 GraphQL APIAmazonAppSync:
-
打开AmazonAppSync 控制台然后选择从头开始构建然后选择启动.
-
将 API 的名称设置为
AppSyncTutorial-PicturesViewer
。 -
选择创建。
这些区域有:AmazonAppSync 控制台会使用 API 密钥身份验证模式为您创建新的 GraphQL API。您可以根据本教程后面的说明,使用控制台设置 GraphQL API 的其余部分,并针对它运行查询。
配置 GraphQL API
您需要配置Amazon您刚创建的 Amazon Cognito 用户池的 AppSync API。
-
选择 Settings 选项卡。
-
在 Authorization Type (授权类型) 部分下,选择 Amazon Cognito User Pool (Amazon Cognito 用户池)。
-
UNDER用户池配置,选择US-WEST-2(对于 )Amazon区域.
-
选择 AppSyncTutorial-UserPool 用户池。
-
选择 DENY 作为默认操作。
-
将 AppId client regex (AppId 客户端正则表达式) 字段保留为空。
-
选择保存。
此 API 现在设置为使用 Amazon Cognito 用户池作为其授权类型。
为 DynamoDB 表配置数据源
创建 DynamoDB 表后,导航到AmazonAppSync GraphQL API 在控制台中选择数据源选项卡。现在,您将在中创建数据源Amazon适用于您刚创建的每个 DynamoDB 表的 AppSync。
-
选择 Data source (数据源) 选项卡。
-
选择 New (新建) 创建新的数据源。
-
对于数据源名称,输入
PicturesDynamoDBTable
。 -
对于数据源类型,选择 Amazon DynamoDB table (Amazon DynamoDB 表)。
-
对于区域,选择 US-WEST-2。
-
从表的列表中,选择appSync 教程-图片DynamoDB 表。
-
在创建或使用现有角色部分,选择现有角色.
-
选择刚刚通过 CloudFormation 模板创建的角色。如果您未更改 ResourceNamePrefix,则角色的名称应为 AppSyncTutorial-DynamoDBRole。
-
选择创建。
对好友表重复相同的过程,DynamoDB 表的名称应为 AppSyncTutorial-Friends,前提是您在创建 CloudFormation 堆栈时未更改 ResourceNamePrefix 参数。
创建 GraphQL 架构
现在数据源已连接到您的 DynamoDB 表,让我们创建 GraphQL 架构。从中的模式编辑器AmazonAppSync 控制台,确保您的架构与以下架构匹配:
schema { query: Query mutation: Mutation } type Mutation { createPicture(input: CreatePictureInput!): Picture! @aws_auth(cognito_groups: ["Admins"]) createFriendship(id: ID!, target: ID!): Boolean @aws_auth(cognito_groups: ["Admins"]) } type Query { getPicturesByOwner(id: ID!): [Picture] @aws_auth(cognito_groups: ["Admins", "Viewers"]) } type Picture { id: ID! owner: ID! src: String } input CreatePictureInput { owner: ID! src: String! }
选择 Save Schema (保存架构) 以保存您的架构。
已使用 @aws_auth 指令对一些架构字段进行注释。由于 API 默认操作配置设置为 DENY,因此此 API 将拒绝不属于 @aws_auth 指令中提及的组成员的所有用户。有关如何保护您的 API 的更多信息,您可以阅读安全性页面。在此情况下,仅管理员用户有权访问 Mutation.createPicture 和 Mutation.createFriendship 字段,而作为 Admins 或 Viewers 组成员的用户可访问 Query.getPicturesByOwner 字段。所有其他用户都没有访问权限。
配置解析程序
现在,您有一个有效的 GraphQL 架构和两个数据源,可以将解析程序附加到架构上的 GraphQL 字段。此 API 提供以下功能:
-
通过 Mutation.createPicture 字段创建图片
-
通过 Mutation.createFriendship 字段创建友好关系
-
通过 Query.getPicture 字段检索图片
Mutation.createPicture
从中的模式编辑器AmazonAppSync 控制台,在右侧选择附加解析程序为了createPicture(input:
CreatePictureInput!): Picture!
. 选择 DynamoDBPicturesDynamoDBTable数据源。在 request mapping template (请求映射模板) 部分中,添加以下模板:
#set($id = $util.autoId()) { "version" : "2018-05-29", "operation" : "PutItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($id), "owner": $util.dynamodb.toDynamoDBJson($ctx.args.input.owner) }, "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args.input) }
在 response mapping template (响应映射模板) 部分中,添加以下模板:
#if($ctx.error) $util.error($ctx.error.message, $ctx.error.type) #end $util.toJson($ctx.result)
创建图片功能已完成。将图片保存在图片表中,使用随机生成的 UUID 作为图片的 ID 并使用 Cognito 用户名作为图片拥有者。
Mutation.createFriendship
从中的模式编辑器AmazonAppSync 控制台,在右侧选择附加解析程序为了createFriendship(id:
ID!, target: ID!): Boolean
. 选择 DynamoDBFriendsDynamoDBTable数据源。在 request mapping template (请求映射模板) 部分中,添加以下模板:
#set($userToFriendFriendship = { "userId" : "$ctx.args.id", "friendId": "$ctx.args.target" }) #set($friendToUserFriendship = { "userId" : "$ctx.args.target", "friendId": "$ctx.args.id" }) #set($friendsItems = [$util.dynamodb.toMapValues($userToFriendFriendship), $util.dynamodb.toMapValues($friendToUserFriendship)]) { "version" : "2018-05-29", "operation" : "BatchPutItem", "tables" : { ## Replace 'AppSyncTutorial-' default below with the ResourceNamePrefix you provided in the CloudFormation template "AppSyncTutorial-Friends": $util.toJson($friendsItems) } }
重要提示:在BatchPutItem请求模板,应该存在 DynamoDB 表的确切名称。默认表名称为 AppSyncTutorial-Friends。如果您使用错误的表名称,则将在 AppSync 尝试代入提供的角色时收到错误。
为了简化本教程,请将友好关系请求视为已批准,并将友好关系条目直接保存到 AppSyncTutorialFriends 表中。
实际上,您将为每个友好关系存储两个项目,因为此关系是双向的。有关表示多对多关系的 Amazon DynamoDB 最佳实践的更多详细信息,请参阅DynamoDB 最佳实践.
在 response mapping template (响应映射模板) 部分中,添加以下模板:
#if($ctx.error) $util.error($ctx.error.message, $ctx.error.type) #end true
注意:确保请求模板包含正确的表名称。默认名称为 AppSyncTutorial-Friends,但如果您更改了 CloudFormation ResourceNamePrefix 参数,则表名称可能不同。
Query.getPicturesByOwner
现在,您已具有友好关系和图片,需要为用户提供查看其好友图片的功能。要满足此要求,您需要先确认请求者是拥有者的好友,最后查询图片。
由于此功能需要两个数据源操作,因此您将创建两个函数。第一个函数 isFriend 将检查请求者和拥有者是否为好友。第二个函数 getPicturesByOwner 在给定所有者 ID 的情况下检索所请求的图片。让我们看看 Query.getPicturesByOwner 字段中有关建议的解析程序的以下执行流:
-
之前映射模板:准备上下文和字段输入参数。
-
isFriend 函数:检查请求者是否为图片的拥有者。如果不是,它将通过对 “好友” 表执行 DynamoDB GetItem 操作来检查请求者和拥有者是否为好友。
-
getPicturesByOwner 函数:使用上的 DynamoDB 查询操作从图片表中检索图片索引全局二级指数。
-
映射模板之后:以便 DynamoDB 属性能够正确地映射到所需的 GraphQL 类型字段。
让我们先创建函数。
isFriend 函数
-
选择 Functions (函数) 选项卡。
-
选择 Create Function (创建函数) 以创建函数。
-
对于数据源名称,输入
FriendsDynamoDBTable
。 -
对于函数名称,请输入 isFriend。
-
在请求映射模板文本区域内,粘贴以下模板:
#set($ownerId = $ctx.prev.result.owner) #set($callerId = $ctx.prev.result.callerId) ## if the owner is the caller, no need to make the check #if($ownerId == $callerId) #return($ctx.prev.result) #end { "version" : "2018-05-29", "operation" : "GetItem", "key" : { "userId" : $util.dynamodb.toDynamoDBJson($callerId), "friendId" : $util.dynamodb.toDynamoDBJson($ownerId) } }
-
在响应映射模板文本区域内,粘贴以下模板:
#if($ctx.error) $util.error("Unable to retrieve friend mapping message: ${ctx.error.message}", $ctx.error.type) #end ## if the users aren't friends #if(!$ctx.result) $util.unauthorized() #end $util.toJson($ctx.prev.result)
-
选择 Create Function (创建函数)。
结果:您创建了isFriendfunction.
getPicturesByOwner 函数
-
选择 Functions (函数) 选项卡。
-
选择 Create Function (创建函数) 以创建函数。
-
对于数据源名称,输入
PicturesDynamoDBTable
。 -
对于函数名称,输入
getPicturesByOwner
。 -
在请求映射模板文本区域内,粘贴以下模板:
{ "version" : "2018-05-29", "operation" : "Query", "query" : { "expression": "#owner = :owner", "expressionNames": { "#owner" : "owner" }, "expressionValues" : { ":owner" : $util.dynamodb.toDynamoDBJson($ctx.prev.result.owner) } }, "index": "owner-index" }
-
在响应映射模板文本区域内,粘贴以下模板:
#if($ctx.error) $util.error($ctx.error.message, $ctx.error.type) #end $util.toJson($ctx.result)
-
选择 Create Function (创建函数)。
结果:您创建了getPicturesByOwnerfunction. 现在已创建函数,请将管道解析程序附加到 Query.getPicturesByOwner 字段。
从中的模式编辑器AmazonAppSync 控制台,在右侧选择附加解析程序为了Query.getPicturesByOwner(id: ID!): [Picture]
. 在以下页面上,选择数据源下拉列表下显示的 Convert to pipeline resolver (转换为管道解析程序) 链接。对之前映射模板使用以下过程:
#set($result = { "owner": $ctx.args.id, "callerId": $ctx.identity.username }) $util.toJson($result)
在 after mapping template (之后映射模板) 部分中,使用以下过程:
#foreach($picture in $ctx.result.items) ## prepend "src://" to picture.src property #set($picture['src'] = "src://${picture['src']}") #end $util.toJson($ctx.result.items)
选择 Create Resolver (创建解析程序)。您已成功附加您的首个管道解析程序。在同一页上,添加您之前创建的两个函数。在函数部分中,选择 Add A Function (添加函数),然后选择或键入第一个函数的名称 isFriend。通过对 getPicturesByOwner 函数执行相同的过程来添加第二个函数。确保 isFriend 函数在列表中先于 getPicturesByOwner 函数显示。您可以使用向上和向下箭头在管道中重新排列函数的执行顺序。
现在,已创建管道解析程序并且您已附加函数,下面让我们测试新创建的 GraphQL API。
测试您的 GraphQL API
首先,您需要通过使用创建的管理员用户执行一些更改来填充图片和友好关系。在左侧AmazonAppSync 控制台,选择查询选项卡。
createPicture 更改
-
InAmazonAppSync 控制台,选择查询选项卡。
-
选择 Login With User Pools (使用用户池登录)。
-
在模态中,输入 CloudFormation 堆栈创建的 Cognito 示例客户端 ID,例如 37solo6mmhh7k4v63cqdfgdg5d。
-
输入您作为参数传递到 CloudFormation 堆栈的用户名。默认值为 nadia。
-
使用发送至您作为参数传递到 CloudFormation 堆栈的电子邮件(例如,UserPoolUserEmail)的临时密码。
-
选择登录。现在,您应看到重命名为 Logout nadia 的按钮,或您创建 CloudFormation 堆栈时选择的任何用户名(即 UserPoolUsername)。
让我们发送一些 createPicture 更改来填充“图片”表。在控制台中执行以下 GraphQL 查询:
mutation { createPicture(input:{ owner: "nadia" src: "nadia.jpg" }) { id owner src } }
响应看上去应与下内容类似:
{ "data": { "createPicture": { "id": "c6fedbbe-57ad-4da3-860a-ffe8d039882a", "owner": "nadia", "src": "nadia.jpg" } } }
让我们再添加几张图片:
mutation { createPicture(input:{ owner: "shaggy" src: "shaggy.jpg" }) { id owner src } }
mutation { createPicture(input:{ owner: "rex" src: "rex.jpg" }) { id owner src } }
您已以管理员用户身份使用 nadia 添加三张图片。
createFriendship 更改
让我们添加友好关系条目。在控制台中执行以下更改。
注意:您仍必须以管理员用户身份(默认管理员用户为)(默认管理员用户为nadia)。
mutation { createFriendship(id: "nadia", target: "shaggy") }
响应应该类似于:
{ "data": { "createFriendship": true } }
nadia 和 shaggy 是好友。rex 与任何人都不是好友。
getPicturesByOwner 查询
在此步骤中,以 nadia 用户身份使用 Cognito 用户池和本教程开头设置的凭证登录。以 nadia 身份检索 shaggy 拥有的图片。
query { getPicturesByOwner(id: "shaggy") { id owner src } }
由于 nadia 和 shaggy 是好友,因此查询应返回对应的图片。
{ "data": { "getPicturesByOwner": [ { "id": "05a16fba-cc29-41ee-a8d5-4e791f4f1079", "owner": "shaggy", "src": "src://shaggy.jpg" } ] } }
同样,如果 nadia 尝试检索自己的图片,也会成功。管道解析程序已经过优化来避免在此情况下运行 isFriend GetItem 操作。尝试以下查询:
query { getPicturesByOwner(id: "nadia") { id owner src } }
如果您在 API 中启用日志记录(在 Settings (设置) 窗格中),将调试级别设置为 ALL (所有),并再次运行相同的查询,则查询将返回字段执行的日志。通过查看日志,您可以确定是否isFriend函数在请求映射模板阶段:
{ "errors": [], "mappingTemplateType": "Request Mapping", "path": "[getPicturesByOwner]", "resolverArn": "arn:aws:appsync:us-west-2:XXXX:apis/XXXX/types/Query/fields/getPicturesByOwner", "functionArn": "arn:aws:appsync:us-west-2:XXXX:apis/XXXX/functions/o2f42p2jrfdl3dw7s6xub2csdfs", "functionName": "isFriend", "earlyReturnedValue": { "owner": "nadia", "callerId": "nadia" }, "context": { "arguments": { "id": "nadia" }, "prev": { "result": { "owner": "nadia", "callerId": "nadia" } }, "stash": {}, "outErrors": [] }, "fieldInError": false }
earlyReturnedValue 键表示 #return 指令所返回的数据。
最后,即使 rex 是 Viewers Cognito UserPool 组的成员,但由于 rex 不是任何人的好友,因此他无法访问 shaggy 或 nadia 拥有的任何图片。如果您以 rex 身份登录控制台并执行以下查询:
query { getPicturesByOwner(id: "nadia") { id owner src } }
您将收到以下未经授权错误:
{ "data": { "getPicturesByOwner": null }, "errors": [ { "path": [ "getPicturesByOwner" ], "data": null, "errorType": "Unauthorized", "errorInfo": null, "locations": [ { "line": 2, "column": 9, "sourceName": null } ], "message": "Not Authorized to access getPicturesByOwner on type Query" } ] }
您已使用管道解析程序成功实现复杂的授权。