【问题标题】:AWS AppSync: pass arguments from parent resolver to childrenAWS AppSync:将参数从父解析器传递给子解析器
【发布时间】:2019-03-01 21:27:44
【问题描述】:

在 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 中是否可以将参数传递给同一请求的所有查询部分?

【问题讨论】:

  • 这种使用请求标头的解决方法可以在有或没有管道的情况下使用 stackoverflow.com/a/58093410/1480391 它很丑,但它是我所知道的唯一允许将信息传递给所有子解析器的解决方案

标签: graphql aws-appsync appsync-apollo-client


【解决方案1】:

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

AppSync 在$context 中有多个容器:

  • 参数
  • 藏匿
  • 来源

argumentsstash 在调用子解析器之前总是被清除,从这些 Cloudwatch 日志中可以看出:

在父执行的最后 - argumentsstash 数据存在。

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

然后在子解析器的最开头 - argumentsstash 始终为空白。

{
"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总是出现在父解析器的响应中,所以我插入了

#set($device = $util.defaultIfNullOrBlank($ctx.args.device, $ctx.source.items[0].device))

进入子解析器的请求映射模板。它将尝试从参数中获取所需的 ID,然后返回到之前的结果。

解决方法 2 - 将参数添加到父响应

修改您的父解析器响应模板以包含参数:

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

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

【讨论】:

  • @joshbour - 你找到了什么解决方案?如果您同意,请将此作为正确答案。这个领域在 AWS 中的记录仍然非常糟糕。这可以帮助其他人节省时间。
  • 添加到这一点,默认情况下 cloudwatch 日志不会在 appsync 上激活。激活它并将“字段解析器日志级别”设置为 ALL 后,您可以清楚地看到文档未能详细解决的上下文对象的内容。从那里你可以做很多其他的事情。
【解决方案2】:

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

##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)

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

【讨论】:

  • 好发现!但它看起来像一个 hack.. 我不确定修改请求标头是 AWS 的预期功能.. 但是由于这种解决方法,我可以将值传播到子解析器
  • 很高兴它有帮助。我很想实现这一点,但还没有找到更好的解决方法,所以希望 AWS 能够尽快实施适当的方法来处理它。
  • 这个答案的美妙之处在于,它不仅适用于儿童,也适用于大儿童:) .. 而且无需将参数从一层传递到另一层。简直太棒了!
【解决方案3】:

将此添加到 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

【讨论】:

    【解决方案4】:

    您应该可以在$context.info.variables ($context.info.variables.consistentRead) 中找到consistentReadhttps://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html#aws-appsync-resolver-context-reference-info

    【讨论】:

      【解决方案5】:

      您不需要将参数传递给子查询。根据您的架构和用例,我认为您可以像下面这样调整架构,以在 AuthorBook 之间建立关系

      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 以 Author.bookID 作为主键,Author.id 作为排序键
      - 创建以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 的作者列表

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          猜你喜欢
          • 2021-01-07
          • 2018-12-20
          • 2019-08-23
          • 2021-03-21
          • 2021-12-03
          • 2017-08-13
          • 2019-02-04
          • 2019-11-25
          • 2017-02-05
          相关资源
          最近更新 更多