以优雅的方式将GraphQL变量传递给第二个函数

时间:2018-02-08 19:00:34

标签: graphql

我正在使用GraphQL,并且无法找到将变量从查询传递到结果的最佳方法。

我有一个这样的架构:

type Fragment {

# The id of the fragment

  id: String!

# The key of the fragment
  key: String!

# The type of component
  component_type: String!

# The params used to build the fragment
  params: JSON

# Component data
  data: JSON

  children: [JSON]

  items: [JSON]


}

该片段是指“cms”片段。我想在解析之后将一些查询数据传递到另一个后端。

我的查询如下:

  query getFragmentsWithItems($keys: [String!]! 
                     $platform: PlatformType 
                     $version: String
                     $userInfo: UserInput
                     $userId: Int
                     ) {                     
    fragmentsWithItems(keys: $keys, platform: $platform, version: $version, userInfo: $userInfo, userId: $userId) {
      key
      data 
      children
      params
      items
    }
  }

问题在于:我在Fragment的data字段中有一些查询数据。在Fragment解决之前,该数据无法使用。我想获取该数据并将其发送到不同的后端。我想用GraphQL来做这件事,我希望做的事情如下:

Fragment: () => {
  async query(obj, args, context, info, {modles}) => {
    const items = await models.getItems(obj.query_string);
  }
}

但我需要传递给原始查询的user_infouser_id。显然,只能从info参数中访问,而这个参数不应该被使用。

我采取的另一条路径是拥有一个手动解析器,它可以做到这样的事情:

const resolveFI = ({ keys, platform, version, userInfo, userId, models }) => {
  if (!keys || !keys.length) {
    return Promise.resolve(null);
  }
  return models.release.get({ platform, version }).then(release =>
    Promise.all(
      keys.map(key =>
        models.fragments.get({
          key,
          platform,
          version,
          release: release.id
        })
      )
    ).then(data => {
      const promises = [];
      data.rows.forEach(r => {
        if (r.data.query_data) {
          const d = {
            // Can just ignore
            filters: r.data.query_data.filters || {},
            user_info: userInfo,
            user_id: userId
          };
          promises.push(
            new Promise(resolve => {
              resolve(
                models.itemSearch.get(d).then(i => ({ items: i.items, ...r }))
              );
            })
          );
        }
        ...etc other backends 

这是有效的,但手动承诺链似乎无法使用GraphQL。

我尝试的最后一件事是让items成为非标量类型,例如:

type Fragment {
items: ItemSearchResult(user_info: UserInput) etc

但是因为我无法将实际结果从Fragment传递给无效的ItemSearchResult。

我意识到这是非常啰嗦的,所以我愿意接受编辑或澄清 我想看看我是否错过了一个更好的方法,或者我是否应该将其打包并让客户端应用程序在获取Fragment数据后再执行项目查询。

1 个答案:

答案 0 :(得分:1)

并不是说你不应该使用info - 这只是一个巨大的痛苦使用;)严肃地说,它是' s意味着用于优化和更高级的用例,因此如果没有更好的解决方案,您就不应该使用它。有些库(like this one)可以用来更容易地解析对象。

那就是说,有几种方法,我想你可以解决这个问题:

1。)在查询解析程序中

getFragmentsWithItems: async (obj, args, ctx, info) => {
  const fragments = await howeverYouDoThat()
  const backendCalls = fragments.map(fragment => {
    // extract whatever data you need from the fragment
    return asyncCallToBackEnd()
  })
  await backendCalls
  return fragments
}

不幸的是,如果你有很多不同的查询返回片段,你最终会得到冗余。

2。)在Fragment类型的现有字段(或另外一个字段)的解析器内部。

如果你走这条路线,并且你需要传递给查询字段的args,你可以使用信息提取它们。或者,您也可以在查询解析程序中改变上下文对象并将这些参数附加到它。然后,所有解析器"下面"查询解析器(如Fragment字段的解析器)可以通过上下文访问这些参数。

3.。)Apollo Server允许您在配置其中间件时定义formatResponse功能。这本质上提供了一个钩子,可以在响应返回给客户端之前对响应执行任何操作。您可以解析该函数​​内部的响应,并从那里调用另一个后端。