使用GraphQL触发嵌套的解析器

时间:2019-01-16 11:53:46

标签: graphql

我认为GraphQL解析器的工作方式缺少明显的东西。这是我的模式(可以有Place的{​​{1}})的简化示例:

AdditionalInformation

以及相关的解析器

import { ApolloServer, gql } from 'apollo-server';

const typeDefs = gql`
  type Place {
    name: String!
    additionalInformation: AdditionalInformation
  }

  type AdditionalInformation {
    foo: String
  }

  type Query {
    places: [Place]
  }
`;

当我执行基本查询时:

const resolvers = {
  Query: {
    places: () => {
        return [{name: 'Barcelona'}];
    }
  },
  AdditionalInformation: {
    foo: () => 'bar'
  }
};

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

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

我总是以{ places { name, additionalInformation { foo } } } 作为null

additionalInformation

这是我的第一个GraphQL应用程序,但我仍然不明白为什么{ "data": { "places": [ { "name": "Barcelona", "additionalInformation": null } ] } } 解析器未自动执行的原因。有什么方法可以让GraphQL知道它必须启动吗?

我已经找到了解决方法,但是我觉得有些棘手:

AdditionalInformation

1 个答案:

答案 0 :(得分:1)

让我们暂时假设additionalInformation是标量,而不是对象类型:

type Place {
  name: String!
  additionalInformation: String
}

places解析器返回的值为:

[{name: 'Barcelona'}]

如果要进行类似的查询...

query {
  places {
    name
    additionalInformation
  }
}

您期望additionalInformation是什么?该值将为null,因为additionalInformation解析器返回的Place对象上没有places属性。

即使我们将additionalInformation设置为Object类型(例如AdditionalInformation),结果也是相同的-additionalInformation字段将解析为null。这是因为默认解析器(当您不为字段指定解析器功能时使用的解析器)只是在寻找与父对象的字段同名的属性。如果找不到该属性,则返回null。

您可能已经为AdditionalInformationfoo)上的字段指定了解析器,但是由于不需要,该解析器不会被解雇,因为整个additionalInformation字段都为空,因此所有关联类型的任何字段的解析程序都将被跳过。

要了解为什么这是理想的行为,请想象一下不同的模式:

type Article {
  title: String!
  content: String!
  image: Image
}

type Image {
  url: String!
  copyright: String!
}

type Query {
  articles: [Article!]!
}

我们有一个数据库,其中有一个articles表和一个images表作为我们的数据层。文章可能有也可能没有与之相关的图像。我的解析器可能看起来像这样:

const resolvers = {
  Query: {
    articles: () => db.getArticlesWithImages()
  }
  Image: {
    copyright: (image) => `©${image.year} ${image.author}`
  }
}

比方说,我们的呼叫getArticlesWithImages解析为一篇没有图片的文章:

[{title:'Foo',内容:'All about foos'}]

作为API的使用者,我要求:

query {
  articles {
    title
    content
    image
  }
}

image字段是可选的。如果返回带有空image字段的article对象,则说明数据库中没有关联的图像。作为前端客户端,我知道不渲染任何图像。

如果GraphQL返回image的值,该怎么办?显然,我们的解析器将中断,因为不会传递任何父值。而且,但是,作为API的使用者,我现在必须解析image的内容,并以某种方式确定图像是否实际上与文章相关联,我应该对此做些什么。

TLDR;

正如您已经建议的,此处的解决方案是为additionalInfo指定一个解析程序。您也可以简单地在您的places解析器中返回该值,即:

return [{name: 'Barcelona', additionalInfo: {}}]

实际上,如果架构的形状与基础数据层的形状对齐,则在处理真实数据时不太可能会遇到此类问题。