本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
在中使用管道解析器 AWS AppSync
注意
我们现在主要支持 APPSYNC _JS 运行时及其文档。请考虑在此处使用 APPSYNC _JS 运行时及其指南。
AWS AppSync 提供了一种通过单位解析器将 GraphQL 字段连接到单个数据源的简单方法。但是,执行单个操作可能还不够。管道解析器提供了对数据来源连续执行操作的能力。在中创建函数API并将其附加到管道解析器。每个函数执行结果将通过管道传输到下一个函数,直到没有要执行的函数为止。借助管道解析器,您现在可以直接在中 AWS AppSync构建更复杂的工作流程。在本教程中,您将构建一个简单的图片查看应用程序,用户可以在其中发布图片和查看其好友发布的图片。
一键设置
如果要在 AWS AppSync 配置了所有解析器和必要 AWS 资源的情况下自动设置 GraphQL 端点,则可以使用以下模板: AWS CloudFormation
此堆栈在您的账户中创建以下资源:
-
IAM AWS AppSync 访问您账户中资源的角色
-
2 个 DynamoDB 表
-
1 个 Amazon Cognito 用户池
-
2 个 Amazon Cognito 用户池组
-
3 个 Amazon Cognito 用户池用户
-
1 AWS AppSync API
在 AWS CloudFormation 堆栈创建过程结束时,您会收到一封针对已创建的三个 Amazon Cognito 用户的电子邮件。每封电子邮件都包含一个临时密码,您使用该密码以 Amazon Cognito 用户身份登录控制台。 AWS AppSync 保存密码完成本教程的剩余部分。
手动设置
如果您更喜欢通过 AWS AppSync控制台手动完成某个 step-by-step过程,请按照以下设置过程进行操作。
设置您的非 AWS AppSync 资源
API与两个 DynamoDB 表通信:一个存储图片的图片表和一个存储用户之间关系的好友表。配置API为使用 Amazon Cognito 用户池作为身份验证类型。以下 AWS CloudFormation 堆栈在账户中设置这些资源。
在 AWS CloudFormation 堆栈创建过程结束时,您会收到一封针对已创建的三个 Amazon Cognito 用户的电子邮件。每封电子邮件都包含一个临时密码,您使用该密码以 Amazon Cognito 用户身份登录控制台。 AWS AppSync保存密码完成本教程的剩余部分。
创建你的 GraphQL API
要在下面创建 GraphQLAPI,请执行以下操作: AWS AppSync
-
打开 AWS AppSync 控制台,选择 “从头开始构建”,然后选择 “开始”。
-
将的名称设置API为
AppSyncTutorial-PicturesViewer
。 -
选择创建。
AWS AppSync 控制台使用API密钥身份验证模式API为您创建一个新的 GraphQL。您可以使用控制台设置 GraphQL 的其余部分,API并在本教程的其余部分中对其运行查询。
配置 GraphQL API
您需要使用刚才创建的 AWS AppSync API Amazon Cognito 用户池进行配置。
-
选择设置选项卡。
-
在 Authorization Type (授权类型) 部分下,选择 Amazon Cognito User Pool (Amazon Cognito 用户池)。
-
在 “用户池配置” 下,为AWS 区域选择 US WEST--2。
-
选择 AppSyncTutorial-UserPool 用户池。
-
选择DENY作为默认操作。
-
将AppId 客户端正则表达式字段留空。
-
选择保存。
现在已设置为使用 Amazon Cognito 用户池作为其授权类型。API
为 DynamoDB 表配置数据来源
创建 DynamoDB 表后,在控制台中导航到您的 AWS AppSync GraphQL,然后API选择 “数据源” 选项卡。现在,你要在中 AWS AppSync 为刚刚创建的每个 DynamoDB 表创建一个数据源。
-
选择 Data source (数据来源) 选项卡。
-
选择 New (新建) 创建新的数据来源。
-
对于数据来源名称,输入
PicturesDynamoDBTable
。 -
对于数据来源类型,选择 Amazon DynamoDB 表。
-
对于区域,请选择美国-WEST 2。
-
从表格列表中,选择 AppSyncTutorial-Pic tures DynamoDB 表。
-
在创建或使用现有角色部分中,选择现有角色。
-
选择刚刚根据 CloudFormation 模板创建的角色。如果您没有更改 ResourceNamePrefix,则该角色的名称应为 AppSyncTutorial-D ynamoDBRole。
-
选择创建。
对好友表重复相同的过程,如果您在创建堆栈时没有更改ResourceNamePrefix参数,则 DynamoDB 表的名称AppSyncTutorial应为-Friends。 CloudFormation
创建 GraphQL 架构
数据来源现已连接到您的 DynamoDB 表,让我们创建一个 GraphQL 架构。在 AWS AppSync 控制台的架构编辑器中,确保您的架构与以下架构相匹配:
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和突变。 createFriendship字段,而属于 “管理员” 或 “查看者” 组的成员的用户可以访问查询。 getPicturesBy所有者字段。所有其他用户都没有访问权限。
配置解析器
现在,您有一个有效的 GraphQL 架构和两个数据来源,可以将解析器附加到架构上的 GraphQL 字段。API提供以下功能:
-
通过 Mutation 创建一张图片。 createPicture字段
-
通过变异建立友谊。 createFriendship字段
-
通过查询检索图片。 getPicture字段
突变。 createPicture
在 AWS AppSync 控制台的架构编辑器中,在右侧选择 Att ach Resolver fo createPicture(input:
CreatePictureInput!): Picture!
r。选择 DynamoDB PicturesDynamoDBTable数据源。在 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 用户名作为图片的所有者。
突变。 createFriendship
在 AWS AppSync 控制台的架构编辑器中,在右侧选择 Att ach Resolver fo createFriendship(id:
ID!, target: ID!): Boolean
r。选择 DynamoDB FriendsDynamoDBTable数据源。在 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-Fri ends。如果您使用了错误的表名,则在 AppSync 尝试担任所提供的角色时会出现错误。
为了简化本教程,请像友谊请求已获批准一样继续操作,并将关系条目直接保存到AppSyncTutorialFriends表格中。
实际上,您将为每个友好关系存储两个项目,因为此关系是双向的。有关 many-to-many表现关系的 Amazon DynamoDB 最佳实践的更多详细信息,请参阅 D ynamoD B 最佳实践。
在 response mapping template (响应映射模板) 部分中,添加以下模板:
#if($ctx.error) $util.error($ctx.error.message, $ctx.error.type) #end true
注意:请确保请求模板包含正确的表名称。默认名称是 AppSyncTutorial-Frien ds,但是如果您更改了 CloudFormation ResourceNamePrefix参数,您的表名可能会有所不同。
查询。 getPicturesBy所有者
现在,您已具有友好关系和图片,需要为用户提供查看其好友图片的功能。要满足此要求,您需要先确认请求者是拥有者的好友,最后查询图片。
由于此功能需要两个数据来源操作,因此您将创建两个函数。第一个函数检查请求者和所有者是否是朋友。isFriend第二个函数 Owner 在给定getPicturesBy所有者 ID 的情况下检索请求的照片。让我们来看看下面针对查询中建议的解析器的执行流程。 getPicturesBy所有者字段:
-
之前映射模板:准备上下文和字段输入参数。
-
isFriend 功能:检查请求者是否是图片的所有者。如果不是,它会通过在好友表上执行 D GetItem ynamoDB 操作来检查请求者和所有者用户是否是朋友。
-
getPicturesBy所有者函数:使用所有者索引全局二级索引上的 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 (创建函数)。
结果:您已创建该isFriend函数。
getPicturesBy所有者函数
-
选择 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 (创建函数)。
结果:您已创建getPicturesBy所有者函数。现在,函数已经创建完毕,请将管道解析器附加到查询。 getPicturesBy所有者字段。
在 AWS AppSync 控制台的架构编辑器中,在右侧选择 Att ach Resolver fo Query.getPicturesByOwner(id: ID!): [Picture]
r。在以下页面上,选择数据来源下拉列表下显示的 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 (创建解析器)。您已成功附加您的首个管道解析器。在同一页上,添加您之前创建的两个函数。在函数部分,选择添加函数,然后选择或键入第一个函数的名称isFriend。按照与 Owner 函数相同的过程添加第二个getPicturesBy函数。确保该isFriend函数首先出现在列表中,然后是 Owner getPicturesBy函数。您可以使用向上和向下箭头在管道中重新排列函数的执行顺序。
现在,管道解析器已经创建完毕并附加了函数,接下来让我们测试一下新创建的 GraphQL API。
测试你的 GraphQL API
首先,您需要通过使用创建的管理员用户执行一些变更来填充图片和友好关系。在 AWS AppSync 控制台的左侧,选择 “查询” 选项卡。
createPicture 突变
-
在 AWS AppSync 控制台中,选择 “查询” 选项卡。
-
选择 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 与任何人都不是好友。
getPicturesBy所有者查询
在此步骤中,以 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(在 “设置” 窗格中),将调试级别设置为 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 指令返回的数据。
最后,尽管雷克斯是 Viewers Cognito UserPool Group 的成员,而且由于雷克斯与任何人都不是朋友,因此他将无法访问 shagg y 或 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" } ] }
您已使用管道解析器成功实现复杂的授权。