Apollo GraphQL:未在突变子字段上调用解析器

Apollo GraphQL: Resolver not called on mutation subfield

我正在尝试 return 来自突变的查询类型,在某些情况下我可以使它工作,但不是我想要的方式。该问题与所使用的查询类型没有特别关系,因为我发现使用 Query.

以外的其他类型也有相同的行为

您可以 运行 并在 https://codesandbox.io/s/1z8kjy8m93

上修改此代码

服务器

const { ApolloServer, gql } = require("apollo-server");

const typeDefs = gql`
  type Query {
    hello(msg: String): String
  }

  type Mutation {
    someMutation(someArg: String): MutationResponse
  }

  type MutationResponse {
    query: Query
    status: String
  }
`;

const resolvers = {
  Query: {
    hello: (root, args, context) => {
      console.log("hello: args = ", args);
      return `${args.msg}, world !`;
    }
  },
  Mutation: {
    someMutation: (root, args, context) => {
      console.log("someMutation: args = ", args);
      return { status: `Mute Mute: ${args.someArg}` };
    }
  }
};

const server = new ApolloServer({
  typeDefs,
  resolvers
});

server.listen().then(({ url }) => {
  console.log(` Server ready at ${url}`);
});

变异

mutation mutateMe($mutationArg: String = "YoloMute !", $helloMsg: String = "Yolhello") {
  someMutation(someArg: $mutationArg) {
    status
    query {
      hello(msg: $helloMsg)
    }
  }
}

回应

{
  "data": {
    "someMutation": {
      "status": "Mute Mute: YoloMute !",
      "query": null
    }
  }
}

我不明白为什么不调用hello解析器而query字段是null

status 字段由 someMutation 解析器适当填充,但由于 query 字段未在那里解析,我希望 GraphQL 为该字段调用现有的解析器,它存在并且应该为 Query 类型调用。

我发现了其他在技术上可行但不令人满意的方法:

这个问题并不是真正特定于 Query 类型,而是涉及您如何设置解析器。

The status field is duly filled by the someMutation resolver, but as the query field is not resolved there I would expect GraphQL to call an existing resolver for this field, which exists and should be called for the Query type.

整个 Query 类型或任何其他类型都没有解析器。解析器仅适用于特定类型的各个字段。当没有为字段定义解析器时,GraphQL 将默认在父对象上查找与该字段同名的 属性,并将 return 的值 属性.

让我们浏览一下您的文档。根级字段是:

someMutation(someArg: $mutationArg)

父值是所有根级突变的根值。除非您使用自定义根值,否则这通常是一个空对象。如果您没有为 Mutation 类型的 someMutation 字段定义解析器,GraphQL 将在您的根值中查找名为 someMutation 的 属性 和 return 那(即未定义,在响应中将被强制为 null)。不过,我们 有一个解析器,它 returns:

{
  status: `Mute Mute: ${args.someArg}`,
}

现在,让我们解析 status 字段。我们的父对象是 return 由父字段的解析器编辑的结果。在这种情况下,上面的对象。 MutationResponse 上的 status 没有解析器,因此 GraphQL 在父级上寻找 status 属性 —— 它会找到一个并使用它。 status 具有标量类型,因此解析器 return 的任何值都将被强制转换为适当的标量值。

query 字段呢?同样,我们没有 MutationResponse 上的 query 字段的解析器。但是,我们在父对象上也没有名为 query 的 属性。因此,GraphQL 所能做的就是 return 该字段为 null。

即使 query 的 return 类型是 ObjectType,因为它解析为 null,该 ObjectType 上字段的任何解析器都不会被触发。返回 null 意味着该对象不存在,因此我们无需费心解析其上的任何字段。想象一下,如果一个字段 returned 一个 User 对象。例如,如果它 return 为空,则无需解析用户名。

那么...我们如何解决这个问题?有两种方式:

query 添加一个 属性 到对象 return 由 someMutation 的解析器编辑,像这样:

{
  status: `Mute Mute: ${args.someArg}`,
  query: {},
}

或者,为字段添加解析器:

MutationResponse: {
  query: () => {},
},

任何一种方式都将确保 query 字段将解析为非空值(在本例中,只是一个空对象)。因为解析的值不是 null 并且 return 类型是 ObjectType(在本例中是 Query), 现在 解析器对于该类型的字段将被触发并且 hello 将按预期解析。