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

时间:2018-12-18 10:45:29

标签: graphql apollo graphql-js apollo-server

我试图从一个突变中返回一个查询类型,在某些情况下我可以使它工作,但不能按我想要的方式工作。问题与使用的查询类型没有特别关系,因为我发现使用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类型调用。

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

1 个答案:

答案 0 :(得分:4)

此问题并非真正针对Query类型,而是涉及您如何设置解析器。

  

状态字段由someMutation解析程序适当填充,但是由于查询字段未解析,因此我希望GraphQL为该字段调用现有的解析程序,该解析器存在并且应针对查询类型进行调用。

没有针对整个Query类型或任何其他类型的解析器。解析程序仅适用于特定类型的各个字段。如果未为字段定义解析器,则GraphQL将默认在父对象上查找与该字段同名的属性,并返回该属性的值。

让我们遍历您的文档。根级字段为:

someMutation(someArg: $mutationArg)

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

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

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

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

尽管query的返回类型是ObjectType,但由于它解析为null,因此不会触发该ObjectType上字段的任何解析器。返回null表示该对象不存在,因此我们无需费心解析该对象上的任何字段。想象一下,如果一个字段返回了一个User对象。如果返回null,则无需解析用户名。

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

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

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

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

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

任何一种方法都将确保query字段将解析为非空值(在这种情况下,只是一个空对象)。由于解析的值不是null,返回类型是ObjectType(在这种情况下为Query),因此将触发该类型字段的现在解析器并且hello将按预期解决。