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 突变。通缉“通用片段”