Graphql AWS AppSync:将参数从父解析程序传递给子解析程序

Graphql AWS AppSync:将参数从父解析程序传递给子解析程序,graphql,aws-appsync,appsync-apollo-client,Graphql,Aws Appsync,Appsync Apollo Client,在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]! a

在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
为空)

我还尝试了
文章(consistentRead:Boolean):[文章]
但运气不好


有人知道在AppSync中是否可以将参数传递给同一请求的所有查询部分吗?

您不需要将参数传递给子查询。根据您的模式和用例,我认为您可以像下面这样调整您的模式,以便在
作者
书籍

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
作为排序键创建表Author
-使用
Book.id
作为主键创建表Book

然后,您必须为
Book.author

这是一个用于插入作者的解析器

{
    "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的作者列表


可以通过响应将参数从父级传递给子级。让我解释一下

AppSync在
$context
中有几个容器:

  • 论据
  • 藏匿
  • 来源
参数
隐藏
总是在调用子解析器之前清除,这从这些Cloudwatch日志中可以看出:

在父执行的最后-
参数
隐藏
数据存在

{
    "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
}
然后在子解析器的最开始处
参数和
隐藏始终为空

{
"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-从上一个结果中获取参数。 在上面的示例中,设备总是出现在父解析器的响应中,因此我插入了

#set($device = $util.defaultIfNullOrBlank($ctx.args.device, $ctx.source.items[0].device))
进入子冲突解决程序的请求映射模板。它将尝试从参数中获取所需的ID,然后返回到前面的结果

解决方法2-将参数添加到父响应 修改父解析器响应模板以包含以下参数:

{
    "items": $utils.toJson($context.result.items),
    "device": "${ctx.args.device}"
}

然后以与第一种解决方法相同的方式在子对象的请求映射模板中检索它。

只需在子对象中使用
$ctx.source.id
,其中
id
是需要从父对象引用的参数

对于我来说,在所有相关的冲突解决程序(嵌套的或与集合实体相关的)中实现可用性是很好的解决方案2(tnx是一个很好的答案),但只适用于子冲突解决程序。 在另一种情况下,当我需要从集合查询(包含实体以外的其他字段)解析实体时,添加到响应映射模板的属性不再可用。 因此,我的解决方案是将其设置为请求头:

##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")))
并从嵌套/其他请求映射模板中读取此值:

#set($profile = $ctx.request.headers.profile)

这使得父参数在相关解析器之间的任何需要的地方都可用。在您的情况下,可能是“设备”和一些默认值,如果不需要,也可能没有该部分。

将此添加到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
中找到
consistentRead
$context.info.variables.consistentRead
):

@joshblour-你找到了什么解决方案?如果您同意,请检查这是正确答案。AWS中对这一领域的记录仍然非常糟糕。这可能会帮助其他人节省时间。好发现!但它看起来像一个黑客。。我不确定修改请求头是否是AWS的预期功能。。但多亏了这个变通方法,我可以将值传播给子解析程序,很高兴它有所帮助。我非常渴望实现这一点,但还没有找到更好的解决办法,所以希望AWS能尽快实施适当的方法来处理。这个答案的美妙之处在于,它不仅适用于儿童,也适用于大孩子:)。。这也不需要将参数从一层传递到另一层。太棒了!这种使用请求头的解决方案可以使用管道,也可以不使用管道。这很难看,但这是我所知道的唯一一种允许将信息传递给所有子解析器的解决方案