如何知道在 GraphQL 查询中请求了哪些字段?

How to know which fields were requested in a GraphQL query?

我写了一个 GraphQL 查询,如下所示:

{
  posts {
    author {
      comments
    }
    comments
  }
}

我想知道如何获取 posts 解析器中请求的子字段的详细信息。

我想这样做是为了避免解析器的嵌套调用。我正在使用 ApolloServer 的 DataSource API.

我可以更改 API 服务器以一次获取所有数据。

我正在使用 ApolloServer 2.0,也欢迎任何其他避免嵌套调用的方法。

这里有几个要点,您可以使用它们来优化查询以提高性能。

  1. 在你的例子中,使用 https://github.com/facebook/dataloader。如果您在您的 通过数据加载器解析器,您将确保调用这些解析器 就一次。这将减少对数据库的调用次数 显着,因为在您的查询中证明了 N+1 问题。
  2. 我不确定您需要在 posts 中获得哪些确切信息 提前,但如果你知道 post 个 ID,你可以考虑做一个 "look ahead" 通过将已知的 ID 传递到评论中。这会 确保您不需要等待 posts 并且您将避免 graphql 树调用,你可以在没有的情况下解决评论 等待 post 秒。这是一篇优化 GraphQL 的好文章 瀑布式请求,您能否给出如何优化您的 使用数据加载器查询并向前看 https://blog.apollographql.com/optimizing-your-graphql-request-waterfalls-7c3f3360b051

您需要解析作为第四个参数传递给解析器的 info 对象。这是对象的类型:

type GraphQLResolveInfo = {
  fieldName: string,
  fieldNodes: Array<Field>,
  returnType: GraphQLOutputType,
  parentType: GraphQLCompositeType,
  schema: GraphQLSchema,
  fragments: { [fragmentName: string]: FragmentDefinition },
  rootValue: any,
  operation: OperationDefinition,
  variableValues: { [variableName: string]: any },
}

您可以自己遍历该领域的 AST,但最好还是使用现有的库。我推荐 graphql-parse-resolve-info。还有许多其他库,但 graphql-parse-resolve-info 是一个非常完整的解决方案,实际上由 postgraphile 在幕后使用。用法示例:

posts: (parent, args, context, info) => {
  const parsedResolveInfo = parseResolveInfo(info)
  console.log(parsedResolveInfo)
}

这将按照这些行记录一个对象:

{
  alias: 'posts',
  name: 'posts',
  args: {},
  fieldsByTypeName: {
    Post: {
      author: {
        alias: 'author',
        name: 'author',
        args: {},
        fieldsByTypeName: ...
      }
      comments: {
        alias: 'comments',
        name: 'comments',
        args: {},
        fieldsByTypeName: ...
      }
    }
  }
}

您可以遍历生成的对象并相应地构造您的 SQL 查询(或一组 API 请求,或其他)。