GraphQL Node.js:确定查询中使用的类型

Posted

技术标签:

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

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


    user(userName: "username") 
        email
        comments
    

在这种情况下,查询具有 User 和 Comment 类型。是否可以使用 node.js 的 graphql-js 或 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

以上是关于GraphQL Node.js:确定查询中使用的类型的主要内容,如果未能解决你的问题,请参考以下文章

Node.js - 如何使用 graphql 获取关联的模型数据?

Node.js Mongodb GraphQL - 突变和查询

node.js graphql/sequelize 服务器为链接属性返回 null

如何从 Node.js/Express 服务器调用 GraphQL API?

用于查询 GraphQL 端点的 Lambda 函数?

这个 GraphQL 查询我做错了啥?