GraphQL 解析器参数的错误顺序(root、args、context)

Wrong order of GraphQL resolver arguments (root, args, context)

我想知道为什么我的参数似乎在我的 GraphQL 解析器中被调换了。我正在使用 express-graphql.

一个解析器示例:

  getLocalDrivers: async (parent, args, ctx) => {
    console.log(ctx);
  }

我写下了文档中出现的参数名称:http://graphql.org/learn/execution/

但是当我调试和检查 objects 时,args object 似乎是第一个,上下文是第二个,parent/root 是第三个。

parent:

Object {location: "020202"}

参数:

IncomingMessage {_readableState: ReadableState, readable: false, domain: null, …}

上下文:

Object {fieldName: "getLocalDrivers", fieldNodes: ....

一些服务器代码:

app.use(
  "/graphql",
  graphqlHTTP({
    schema,
    graphiql: true,
    rootValue: rootResolver
  })
);

我的根解析器:

var rootResolver = {
     getLocalDrivers: async (obj, args, ctx) => {
       console.log(ctx);
  }
}

架构:

var { buildSchema } = require("graphql");
var schema = buildSchema(`
  type Query {
    getLocalDrivers(location: String): [Driver]
  }

  type Driver {
    name: String
    location: String    
  }`);

如果为一个字段定义了一个resolve函数,当GraphQL解析该字段时,它将向该函数传递四个个参数:

  1. 父字段解析为的值(通常称为 objroot
  2. 该字段的参数
  3. 上下文
  4. 描述整个 GraphQL 请求的信息对象

如果特定字段缺少解析函数,GraphQL 将使用默认解析器,它只在父字段上搜索 属性 并在找到时使用它。

所以你的 getLocalDrivers 查询可以 return 一个 Driver 对象的数组,只要 Driver 对象有一个 name 属性,name 字段 将解析为 属性 的值。

巧合的是,Driver 对象上的 name 属性 也可能是一个函数。在这种情况下,GraphQL 将调用该函数来获取其 return 值。与解析器非常相似,GraphQL 将一些信息作为参数传递给此函数,即 1) 参数,2) 上下文和 3) 信息对象。以这种方式解析字段时,将省略 "obj" 参数。

好的,那么根呢?

根对象只是用作 "parent field value" 的对象,用于查询和变更,这些字段与其他所有内容一样。

因此,如果您没有为 getLocalDrivers 定义 "resolve" 函数(例如,因为您使用 buildQuery 编译了架构),GraphQL 将使用默认解析器,并且使用您传入的根对象作为 "parent field value"。它看到一个getLocalDrivers,但是如上所述,因为这是一个函数,所以它用上面提到的三个参数调用那个函数。

那么这里的教训是什么?

不要使用 root。

说真的。将您的模式定义为对象,或者如果您想使用 GraphQL 模式语言写出模式,请使用 graphql-tools——makeExecutableSchema 使处理解析器变得容易得多。

const typeDefs = `
  type Query {
    getLocalDrivers(location: String): [Driver]
  }

  type Driver {
    name: String
    location: String    
  }
`
const resolvers = {
  Query: {
    getLocalDrivers: (obj, args, ctx) => {
       console.log({obj, args, ctx})
    }
  }
}
const schema = makeExecutableSchema({
  typeDefs,
  resolvers,
})