AWS AppSync:将参数从父解析器传递给子解析器
AWS AppSync: pass arguments from parent resolver to children
在 AWS AppSync 中,在主查询上发送的参数似乎没有转发给所有子解析器。
type Query {
article(id: String!, consistentRead: Boolean): Article
book(id: String!, consistentRead: Boolean): Book
}
type Article {
title: String!
id: String!
}
type Book {
articleIds: [String]!
articles: [Article]!
id: String!
}
当我打电话时:
query GetBook {
book(id: 123, consistentRead: true) {
articles {
title
}
}
}
获取书籍的第一个查询在 $context.arguments
中接收 consistentRead
参数,但随后检索文章的查询没有。 ($context.arguments
为空)
我也在 book
中尝试了 articles(consistentRead: Boolean): [Article]!
,但没有成功。
有谁知道在 AppSync 中是否可以将参数传递给同一请求的所有查询部分?
您不需要将参数传递给子查询。根据您的模式和用例,我认为您可以像下面这样调整您的模式以在 Author
和 Book
之间建立关系
type Author {
# parent's id
bookID: ID!
# author id
id: ID!
name: String!
}
type Book {
id: ID!
title: String!
author: [Author]!
}
type Mutation {
insertAuthor(bookID: ID!, id: ID!, name: String!): Author
insertBook(id: ID!, title: String!): Book
}
type Query {
getBook(id: ID!): Book
}
- 使用 Author.bookID
作为主键和 Author.id
作为排序键创建 table 作者
- 使用 Book.id
作为主键
创建 table 本书
然后,您必须为 Book.author
附加解析器
这是 insertAuthor
变异的解析器
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key" : {
"bookID" : $util.dynamodb.toDynamoDBJson($ctx.args.bookID),
"id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
},
"attributeValues" : {
"name" : $util.dynamodb.toDynamoDBJson($ctx.args.name)
}
}
并且当您查询 getBook
时,您将获得与以下图书 ID 相同的作者列表
可以通过响应将参数从 parent 传递到 child。让我解释一下...
AppSync 内部有多个容器 $context
:
- 参数
- 藏起来
- 来源
arguments
和 stash
在调用 child 解析器之前总是被清除,从这些 Cloudwatch 日志中可以明显看出:
在 parent 执行的最后 - arguments
和 stash
数据存在。
{
"errors": [],
"mappingTemplateType": "After Mapping",
"path": "[getLatestDeviceState]",
"resolverArn": "arn:aws:appsync:us-east-1:xxx:apis/yyy/types/Query/fields/getLatestDeviceState",
"context": {
"arguments": {
"device": "ddddd"
},
"prev": {
"result": {
"items": [
{
"version": "849",
"device": "ddddd",
"timestamp": "2019-01-29T12:18:34.504+13:00"
}
]
}
},
"stash": {"testKey": "testValue"},
"outErrors": []
},
"fieldInError": false
}
然后 在 child 解析器的开头 - arguments
和 stash
始终为空白。
{
"errors": [],
"mappingTemplateType": "Before Mapping",
"path": "[getLatestDeviceState, media]",
"resolverArn": "arn:aws:appsync:us-east-1:yyy:apis/xxx/types/DeviceStatePRODConnection/fields/media",
"context": {
"arguments": {},
"source": {
"items": [
{
"version": "849",
"device": "ddddd",
"timestamp": "2019-01-29T12:18:34.504+13:00"
}
]
},
"stash": {},
"outErrors": []
},
"fieldInError": false
}
解决方法 1 - 从之前的结果中获取参数。
在上面的示例中,device
始终出现在 parent 解析器的响应中,因此我插入了
#set($device = $util.defaultIfNullOrBlank($ctx.args.device, $ctx.source.items[0].device))
进入 child 解析器 的 请求映射模板。它将尝试从参数中获取所需的 ID,然后返回到先前的结果。
解决方法 2 - 将参数添加到 parent 响应
修改您的 parent 解析器响应模板以包含参数:
{
"items": $utils.toJson($context.result.items),
"device": "${ctx.args.device}"
}
然后在 child 的请求映射模板中检索它,方法与第一个解决方法相同。
只需在 child 中使用 $ctx.source.id
,其中 id
是您需要从 parent 引用的参数。
实现所有相关解析器(嵌套或 collection-entity 相关)的可用性对我来说很好 解决方法 2(tnx Max答案),但仅适用于 child 解析器。
在另一种情况下,当我需要从 collection 查询(包含除实体之外的其他字段)解析实体时,添加到响应映射模板的 属性 不再可用。
所以我的解决方案是将其设置为请求 headers:
##Set parent query profile parameter to headers to achieve availability accross related resolvers.
#set( $headers = $context.request.headers )
$util.qr($headers.put("profile", $util.defaultIfNullOrBlank($context.args.profile, "default")))
并从您的 nested/other 请求映射模板中读取此值:
#set($profile = $ctx.request.headers.profile)
这使得 parent 参数可以在相关解析器之间的任何需要的地方使用。在您的情况下,它将是 'device' 和一些默认值,或者如果不需要则没有该部分。
将此添加到 BookQuery 响应映射模板
#set( $book = $ctx.result )
#set($Articles = []);
#foreach($article in $book.articles)
#set( $newArticle = $article )
$util.qr($newArticle.put("bookID", $book.id))
$util.qr($Articles.add($newArticle))
#end
$util.qr($book.put("articles", $Articles))
$util.toJson($book)
现在,每篇文章都会有 bookID
您应该能够在 $context.info.variables
($context.info.variables.consistentRead
) 中找到 consistentRead
:
https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html#aws-appsync-resolver-context-reference-info
在 AWS AppSync 中,在主查询上发送的参数似乎没有转发给所有子解析器。
type Query {
article(id: String!, consistentRead: Boolean): Article
book(id: String!, consistentRead: Boolean): Book
}
type Article {
title: String!
id: String!
}
type Book {
articleIds: [String]!
articles: [Article]!
id: String!
}
当我打电话时:
query GetBook {
book(id: 123, consistentRead: true) {
articles {
title
}
}
}
获取书籍的第一个查询在 $context.arguments
中接收 consistentRead
参数,但随后检索文章的查询没有。 ($context.arguments
为空)
我也在 book
中尝试了 articles(consistentRead: Boolean): [Article]!
,但没有成功。
有谁知道在 AppSync 中是否可以将参数传递给同一请求的所有查询部分?
您不需要将参数传递给子查询。根据您的模式和用例,我认为您可以像下面这样调整您的模式以在 Author
和 Book
type Author {
# parent's id
bookID: ID!
# author id
id: ID!
name: String!
}
type Book {
id: ID!
title: String!
author: [Author]!
}
type Mutation {
insertAuthor(bookID: ID!, id: ID!, name: String!): Author
insertBook(id: ID!, title: String!): Book
}
type Query {
getBook(id: ID!): Book
}
- 使用 Author.bookID
作为主键和 Author.id
作为排序键创建 table 作者
- 使用 Book.id
作为主键
然后,您必须为 Book.author
这是 insertAuthor
变异的解析器
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key" : {
"bookID" : $util.dynamodb.toDynamoDBJson($ctx.args.bookID),
"id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
},
"attributeValues" : {
"name" : $util.dynamodb.toDynamoDBJson($ctx.args.name)
}
}
并且当您查询 getBook
时,您将获得与以下图书 ID 相同的作者列表
可以通过响应将参数从 parent 传递到 child。让我解释一下...
AppSync 内部有多个容器 $context
:
- 参数
- 藏起来
- 来源
arguments
和 stash
在调用 child 解析器之前总是被清除,从这些 Cloudwatch 日志中可以明显看出:
在 parent 执行的最后 - arguments
和 stash
数据存在。
{
"errors": [],
"mappingTemplateType": "After Mapping",
"path": "[getLatestDeviceState]",
"resolverArn": "arn:aws:appsync:us-east-1:xxx:apis/yyy/types/Query/fields/getLatestDeviceState",
"context": {
"arguments": {
"device": "ddddd"
},
"prev": {
"result": {
"items": [
{
"version": "849",
"device": "ddddd",
"timestamp": "2019-01-29T12:18:34.504+13:00"
}
]
}
},
"stash": {"testKey": "testValue"},
"outErrors": []
},
"fieldInError": false
}
然后 在 child 解析器的开头 - arguments
和 stash
始终为空白。
{
"errors": [],
"mappingTemplateType": "Before Mapping",
"path": "[getLatestDeviceState, media]",
"resolverArn": "arn:aws:appsync:us-east-1:yyy:apis/xxx/types/DeviceStatePRODConnection/fields/media",
"context": {
"arguments": {},
"source": {
"items": [
{
"version": "849",
"device": "ddddd",
"timestamp": "2019-01-29T12:18:34.504+13:00"
}
]
},
"stash": {},
"outErrors": []
},
"fieldInError": false
}
解决方法 1 - 从之前的结果中获取参数。
在上面的示例中,device
始终出现在 parent 解析器的响应中,因此我插入了
#set($device = $util.defaultIfNullOrBlank($ctx.args.device, $ctx.source.items[0].device))
进入 child 解析器 的 请求映射模板。它将尝试从参数中获取所需的 ID,然后返回到先前的结果。
解决方法 2 - 将参数添加到 parent 响应
修改您的 parent 解析器响应模板以包含参数:
{
"items": $utils.toJson($context.result.items),
"device": "${ctx.args.device}"
}
然后在 child 的请求映射模板中检索它,方法与第一个解决方法相同。
只需在 child 中使用 $ctx.source.id
,其中 id
是您需要从 parent 引用的参数。
实现所有相关解析器(嵌套或 collection-entity 相关)的可用性对我来说很好 解决方法 2(tnx Max答案),但仅适用于 child 解析器。 在另一种情况下,当我需要从 collection 查询(包含除实体之外的其他字段)解析实体时,添加到响应映射模板的 属性 不再可用。 所以我的解决方案是将其设置为请求 headers:
##Set parent query profile parameter to headers to achieve availability accross related resolvers.
#set( $headers = $context.request.headers )
$util.qr($headers.put("profile", $util.defaultIfNullOrBlank($context.args.profile, "default")))
并从您的 nested/other 请求映射模板中读取此值:
#set($profile = $ctx.request.headers.profile)
这使得 parent 参数可以在相关解析器之间的任何需要的地方使用。在您的情况下,它将是 'device' 和一些默认值,或者如果不需要则没有该部分。
将此添加到 BookQuery 响应映射模板
#set( $book = $ctx.result )
#set($Articles = []);
#foreach($article in $book.articles)
#set( $newArticle = $article )
$util.qr($newArticle.put("bookID", $book.id))
$util.qr($Articles.add($newArticle))
#end
$util.qr($book.put("articles", $Articles))
$util.toJson($book)
现在,每篇文章都会有 bookID
您应该能够在 $context.info.variables
($context.info.variables.consistentRead
) 中找到 consistentRead
:
https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html#aws-appsync-resolver-context-reference-info