【问题标题】:Apollo GraphQL: Resolver not called on mutation subfieldApollo GraphQL:未在突变子字段上调用解析器
【发布时间】: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 类型。

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

【问题讨论】:

    标签: graphql apollo graphql-js apollo-server


    【解决方案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),所以我什至无法表达我多么感激像你这样的人帮助像我这样的人!
    猜你喜欢
    • 2020-01-28
    • 1970-01-01
    • 2020-09-11
    • 2021-01-25
    • 2017-01-11
    • 2018-10-04
    • 1970-01-01
    • 2020-04-24
    • 2020-07-15
    相关资源
    最近更新 更多