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

Posted

技术标签:

【中文标题】Apollo GraphQL:未在突变子字段上调用解析器【英文标题】:Apollo GraphQL: Resolver not called on mutation subfield 【发布时间】:2019-05-18 18:28:04 【问题描述】:

我正在尝试从突变中返回一个查询类型,在某些情况下我可以使其工作,但不是我想要的方式。该问题与所使用的 Query 类型并没有特别相关,因为我发现使用 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 类型。

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

直接返回查询类型有效: https://codesandbox.io/s/ovr9zpwr7q 架构中的重复行 作品:https://codesandbox.io/s/l4yrqzmq6l

【问题讨论】:

【参考方案1】:

此问题并非真正特定于 Query 类型,而是与您如何设置解析器有关。

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

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

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

someMutation(someArg: $mutationArg)

父值是所有根级突变的根值。除非您使用自定义根值,否则这通常是一个空对象。如果您没有为 Mutation 类型的 someMutation 字段定义解析器,GraphQL 将在您的根值中查找名为 someMutation 的属性并返回该属性(即未定义,在回复)。不过,我们确实有一个解析器,它会返回:


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

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

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

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

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

query 的属性添加到someMutation 的解析器返回的对象中,如下所示:


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

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

MutationResponse: 
  query: () => ,
,

无论哪种方式都将确保query 字段将解析为非空值(在这种情况下,只是一个空对象)。因为解析的值不是null,而返回类型是ObjectType(在本例中为Query),现在将触发该类型字段的解析器,hello 将解析正如预期的那样。

【讨论】:

我的词汇混淆了,我的意思不是“查询类型的解析器”而是“查询类型的这个字段的解析器”。 非常感谢您的详细回答!你只是让我比以前更深入地了解了 graphql 的工作原理。我在这个问题上被困了 3 周(还探索了很多其他方法,比如批处理或 refetchQueries),所以我什至无法表达我多么感激像你这样的人帮助像我这样的人!

以上是关于Apollo GraphQL:未在突变子字段上调用解析器的主要内容,如果未能解决你的问题,请参考以下文章

Apollo GraphQL:从服务器调用突变?

能够使用相同的字段扩展所有 Apollo/GraphQL 突变。通缉“通用片段”

Apollo GraphQL 嵌套突变

使用 Prisma 和 Apollo 调用多个 GraphQL 突变的正确方法是啥

用于在突变字段上映射数组的 GraphQL 语法

React Native、GraphQL、Apollo - 如何创建批量插入突变