使用GraphQL的触发器嵌套解析器

使用GraphQL的触发器嵌套解析器,graphql,Graphql,我想我在GraphQL解析器的工作方式中遗漏了一些明显的东西。这是我的模式的简化示例(可以包含附加信息的位置): 从“阿波罗服务器”导入{ApolloServer,gql}; 常量typeDefs=gql` 打印位置{ 名字:字符串! 附加信息:附加信息 } 类型附加信息{ foo:String } 类型查询{ 地点:[地点] } `; 以及相关的解析程序: const解析器={ 查询:{ 地点:()=>{ return[{name:'Barcelona'}]; } }, 其他信息:{ foo

我想我在GraphQL解析器的工作方式中遗漏了一些明显的东西。这是我的模式的简化示例(可以包含
附加信息的
位置
):

从“阿波罗服务器”导入{ApolloServer,gql};
常量typeDefs=gql`
打印位置{
名字:字符串!
附加信息:附加信息
}
类型附加信息{
foo:String
}
类型查询{
地点:[地点]
}
`;
以及相关的解析程序

const解析器={
查询:{
地点:()=>{
return[{name:'Barcelona'}];
}
},
其他信息:{
foo:()=>“酒吧”
}
};
const server=new ApolloServer({typeDefs,resolvers});
server.listen().then({url})=>{
log(`API server ready at${url}`);
});
执行基本查询时:

{
  places {
    name,
    additionalInformation {
      foo
    }
  }
}
我总是得到
null
作为
附加信息

{
  "data": {
    "places": [
      {
        "name": "Barcelona",
        "additionalInformation": null
      }
    ]
  }
}
这是我的第一个GraphQL应用程序,我仍然不明白为什么
附加信息
解析器没有自动执行。有没有办法让GraphQL知道它必须启动它

我找到了这个解决方法,但我觉得有点棘手:

地点:{
附加信息:()=>{return{};}
}}

让我们暂时假设
附加信息
是标量,而不是对象类型:

type Place {
  name: String!
  additionalInformation: String
}
places
解析器返回的值为:

[{name: 'Barcelona'}]
如果你要做一个类似的查询

query {
  places {
    name
    additionalInformation
  }
}
您希望
其他信息是什么?它的值将为null,因为由
places
解析程序返回的
Place
对象上没有
additionalInformation
属性

即使我们将
附加信息
设为对象类型(如
附加信息
),结果也是一样的--
附加信息
字段将解析为空。这是因为默认解析程序(在不为字段指定解析程序函数时使用的解析程序)只是查找与父对象上的字段同名的属性。如果找不到该属性,则返回null

您可能已经为
AdditionalInformation
foo
)上的某个字段指定了冲突解决程序,但由于没有必要,因此从未触发此冲突解决程序--整个
AdditionalInformation
字段为空,因此跳过关联类型的任何字段的所有冲突解决程序

要理解为什么这是一种可取的行为,请想象一个不同的模式:

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

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

type Query {
  articles: [Article!]!
}
我们有一个数据库,其中包含一个
文章
表和一个
图像
表作为我们的数据层。文章可能有也可能没有与之关联的图像。我的解析器可能如下所示:

const resolvers = {
  Query: {
    articles: () => db.getArticlesWithImages()
  }
  Image: {
    copyright: (image) => `©${image.year} ${image.author}`
  }
}
假设我们的调用
getArticlesWithImages
解析为一篇没有图像的文章:

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

作为API的消费者,我请求:

query {
  articles {
    title
    content
    image
  }
}
图像
字段是可选的。如果我得到一个带有null
image
字段的文章对象,我就知道数据库中没有关联的图像。作为前端客户端,我知道不渲染任何图像

如果GraphQL为
图像返回一个值,不管结果如何,会发生什么情况?显然,我们的解析器会崩溃,因为它不会被传递任何类型的父值。此外,作为API的消费者,我现在必须解析
image
的内容,并以某种方式确定某个图像是否与文章相关,我应该对其进行处理

太长,读不下去了 正如您所建议的,这里的解决方案是为
additionalInfo
指定一个解析器。您也可以在
位置
解析器中简单地返回该值,即:

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

实际上,如果模式的形状与底层数据层的形状一致,则在处理真实数据时不太可能遇到此类问题。

让我们暂时假设
附加信息
是标量,而不是对象类型:

type Place {
  name: String!
  additionalInformation: String
}
places
解析器返回的值为:

[{name: 'Barcelona'}]
如果你要做一个类似的查询

query {
  places {
    name
    additionalInformation
  }
}
您希望
其他信息是什么?它的值将为null,因为由
places
解析程序返回的
Place
对象上没有
additionalInformation
属性

即使我们将
附加信息
设为对象类型(如
附加信息
),结果也是一样的--
附加信息
字段将解析为空。这是因为默认解析程序(在不为字段指定解析程序函数时使用的解析程序)只是查找与父对象上的字段同名的属性。如果找不到该属性,则返回null

您可能已经为
AdditionalInformation
foo
)上的某个字段指定了冲突解决程序,但由于没有必要,因此从未触发此冲突解决程序--整个
AdditionalInformation
字段为空,因此跳过关联类型的任何字段的所有冲突解决程序

要理解为什么这是一种可取的行为,请想象一个不同的模式:

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

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

type Query {
  articles: [Article!]!
}
我们有一个数据库,其中包含一个
文章
表和一个
图像
表作为我们的数据层。文章可能有也可能没有与之关联的图像。我的解析器可能如下所示:

const resolvers = {
  Query: {
    articles: () => db.getArticlesWithImages()
  }
  Image: {
    copyright: (image) => `©${image.year} ${image.author}`
  }
}
假设我们的调用
getArticlesWithImages
解析为一篇没有图像的文章:

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

作为API的消费者,我请求:

query {
  articles {
    title
    content
    image
  }
}
图像
字段是可选的。如果我得到一个带有null
image
字段的文章对象,我就知道数据库中没有关联的图像。作为前端客户端,我知道不渲染任何图像

会发生什么