【问题标题】:GraphQL Node.js: determine what types are used within a queryGraphQL Node.js:确定查询中使用的类型
【发布时间】:2019-04-06 21:34:00
【问题描述】:

假设我有一个具有以下类型的架构:用户、评论、帖子、图像;给定查询和模式,是否可以确定查询中使用的 GraphQL 类型? 例如如果客户有查询

{
    user(userName: "username") {
        email
        comments
    }
}

在这种情况下,查询具有 User 和 Comment 类型。是否可以使用 node.js 的 graphql-js 或 graphql 包以编程方式确定?

【问题讨论】:

    标签: javascript node.js graphql graphql-js express-graphql


    【解决方案1】:

    对于遇到此问题的其他人,我在访问和 TypeInfo 中找到了答案 这是一个函数,它接受 GraphQL 查询(文档)和模式,并返回正在使用的模式中的数据类型。

    import { visit } from 'graphql/language/visitor'
    import { parse } from 'graphql/language'
    import { TypeInfo, visitWithTypeInfo } from 'graphql'
    import { schema as _schema } from '../src/schema/schema'
    
    const getQueryTypes = (schema, query) => {
        const typeInfo = new TypeInfo(schema)
        var typesMap = {}
        var visitor = {
            enter(node) {
                typeInfo.enter(node)
                typesMap[typeInfo.getType()] = true
            },
            leave(node) {
                typesMap[typeInfo.getType()] = true
                typeInfo.leave(node)
            }
        }
        visit(parse(query), visitWithTypeInfo(typeInfo, visitor))
        return Object.keys(typesMap)
    }
    
    const _query = `
        query {
            ...
        } 
    `
    
    console.log(getQueryTypes(_schema, _query))
    

    【讨论】:

    • visitWithTypeInfo 是要走的路。但无需手动执行 enter(node) 和 leave(node),因为 visitWithTypeInfo 将创建一个在幕后自动执行此操作的访问者。
    【解决方案2】:

    给定一个表示某些 GraphQL 操作的有效文档字符串,您可以将字符串解析为 AST。

    import { parse, validate } from 'graphql' 
    
    const document = parse(someDocumentString)
    // if you want to validate your document to verify it matches your schema
    const errors = validate(schema, document)
    

    AFAIK,如果您需要的话,没有用于获取文档中类型数组的实用函数,但您可以遍历 AST 并从中收集任何信息。例如,以下是 GraphiQL 如何生成变量映射到其对应类型的方法:

    import { typeFromAST } from 'graphql'
    
    export function collectVariables(schema, documentAST) {
      const variableToType = Object.create(null);
      documentAST.definitions.forEach(definition => {
        if (definition.kind === 'OperationDefinition') {
          const variableDefinitions = definition.variableDefinitions;
          if (variableDefinitions) {
            variableDefinitions.forEach(({ variable, type }) => {
              const inputType = typeFromAST(schema, type);
              if (inputType) {
                variableToType[variable.name.value] = inputType;
              }
            });
          }
        }
      });
      return variableToType;
    }
    

    【讨论】:

      【解决方案3】:

      你必须使用GraphQLObjectType创建类型,例如:

      export default new GraphQLObjectType(
        ({
          name: 'User',
          description: 'Represents a User',
          fields: () => ({
            _id: {
              type: GraphQLNonNull(GraphQLString),
              resolve: user => user._id,
            },
            name: {
              type: GraphQLNonNull(GraphQLString),
              description: 'Name of the user',
              resolve: user => user.name,
            },
            createdAt: {
              type: GraphQLString,
              description: '',
              resolve: user => user.createdAt.toISOString(),
            },
            updatedAt: {
              type: GraphQLString,
              description: '',
              resolve: user => user.updatedAt.toISOString(),
            },
          }),
        }: GraphQLObjectTypeConfig<User, GraphQLContext>),
      );
      

      然后你可以在另一个类型上使用这个UserType,例如声明type: GraphQLNonNull(UserType)

      https://graphql.org/graphql-js/constructing-types/

      希望对你有帮助:)

      【讨论】:

      • 感谢丹尼斯的快速回复,我了解如何创建 GraphQL 类型。我想知道的是,如果我有一个查询和一个架构,是否有一个函数/方法可以告诉我查询中使用了架构中的哪些类型。我已将我的 GraphiQL UI 与我的 GraphQL 服务器分开。它们作为单独的应用程序运行,我希望 GraphiQL UI 在将查询发送到 GraphQL 服务器之前能够确定查询中使用了哪些类型。
      • @user277931 GraphiQL 针对提供的 GraphQL 端点执行自省查询,并根据结果重新生成服务器的架构。此模式用于提供您在使用 GraphiQL 时看到的各种功能,例如 linting、自动完成和文档面板。所以 wrt GraphiQL,它已经知道任何给定字段或参数的类型。所有这些都在引擎盖下为您处理。您到底想通过 GraphiQL 完成什么?
      • @DanielRearden 我们的 graphql 服务器需要处理不同解析器的授权。例如一些客户端可以看到用户和帖子,而其他客户端只能看到用户。为此,我们的客户端必须传入一个名为“Data-Types”的 HTTP 标头,以指定他们尝试发送的类型。它看起来类似于“Data-Types: User,Post”。为了使开发人员更容易做到这一点,我们希望我们的 Graphiql 实例自动确定要包含在“Data-Types”标头中的类型。这有意义吗?
      • 有趣的用例。对于它的价值,您也许还可以创建一个“访问者”(您可以查看示例 github.com/graphql/graphql-js/tree/master/src/validation/rules 的验证规则),然后使用文档的 AST 和访问者对象调用 visit
      猜你喜欢
      • 2020-05-05
      • 2017-04-18
      • 2020-12-19
      • 2022-10-19
      • 2020-05-24
      • 2022-07-10
      • 1970-01-01
      • 2021-09-09
      • 2019-09-23
      相关资源
      最近更新 更多