使用 GraphQL 触发嵌套解析器 [英] Trigger nested resolvers with GraphQL
问题描述
我想我在 GraphQL 解析器的工作方式中遗漏了一些明显的东西.这是我的架构(一个可以有AdditionalInformation
的Place
)的简化示例:
I think I'm missing something obvious in the way GraphQL resolvers work. This is a simplified example of my schema (a Place
that can have 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
:
I always get null
as the additionalInformation
:
{
"data": {
"places": [
{
"name": "Barcelona",
"additionalInformation": null
}
]
}
}
这是我的第一个 GraphQL 应用程序,我仍然不明白为什么不自动执行 AdditionalInformation
解析器.有没有办法让 GraphQL 知道它必须触发它?
It's my first GraphQL app, and I still don't get why the AdditionalInformation
resolver is not automatically executed. Is there some way to let GraphQL know it has to fire it?
我找到了这个解决方法,但我觉得它有点棘手:
I've found this workaround but I find it a bit tricky:
Place: {
additionalInformation: () => { return {}; }
}}
推荐答案
让我们暂时假设 additionalInformation
是一个标量,而不是一个对象类型:
Let's assume for a moment that additionalInformation
was a Scalar, and not an Object type:
type Place {
name: String!
additionalInformation: String
}
places
解析器返回的值是:
[{name: 'Barcelona'}]
如果您要进行类似的查询...
If you were to make a similar query...
query {
places {
name
additionalInformation
}
}
您希望 additionalInformation
是什么?它的值将为 null,因为 places
解析器返回的 Place
对象上没有 additionalInformation
属性.
What would you expect additionalInformation
to be? It's value will be null because there is no additionalInformation
property on the Place
object returned by the places
resolver.
即使我们使 additionalInformation
成为对象类型(如 AdditionalInformation
),结果也是一样的——additionalInformation
字段将解析为空值.这是因为默认解析器(当您没有为字段指定解析器函数时使用的解析器)只是查找与父对象上的字段同名的属性.如果找不到该属性,则返回 null.
Even if we make additionalInformation
an Object type (like AdditionalInformation
), the result is the same -- the additionalInformation
field will resolve to null. That's because the default resolver (the one used when you don't specify a resolver function for a field) simply looks for a property with the same name as the field on the parent object. If it fails to find that property, it returns null.
您可能已经为 AdditionalInformation
(foo
) 上的一个字段指定了一个解析器,但是这个解析器永远不会被触发,因为不需要——整个 additionalInformation
字段为空,因此将跳过关联类型的任何字段的所有解析器.
You may have specified a resolver for a field on AdditionalInformation
(foo
), but this resolver is never fired because there's no need -- the whole additionalInformation
field is null so all of the resolvers for any fields of the associated type are skipped.
要理解为什么这是一种理想的行为,请想象一个不同的模式:
To understand why this is a desirable behavior, imagine a different schema:
type Article {
title: String!
content: String!
image: Image
}
type Image {
url: String!
copyright: String!
}
type Query {
articles: [Article!]!
}
我们有一个数据库,其中包含一个 articles
表和一个 images
表作为我们的数据层.一篇文章可能有也可能没有与之相关的图像.我的解析器可能如下所示:
We have a database with an articles
table and an images
table as our data layer. An article may or may not have an image associated with it. My resolvers might look like this:
const resolvers = {
Query: {
articles: () => db.getArticlesWithImages()
}
Image: {
copyright: (image) => `©${image.year} ${image.author}`
}
}
假设我们的调用 getArticlesWithImages
解析为一篇没有图像的文章:
Let's say our call getArticlesWithImages
resolves to a single article with no image:
[{ title: 'Foo', content: 'All about foos' }]
[{ title: 'Foo', content: 'All about foos' }]
作为 API 的使用者,我请求:
As a consumer of the API, I request:
query {
articles {
title
content
image
}
}
image
字段是可选的.如果我返回一个带有空 image
字段的文章对象,我知道数据库中没有关联的图像.作为前端客户,我知道不要渲染任何图像.
The image
field is optional. If I get back an article object with a null image
field, I understand there was no associated image in the db. As a front end client, I know not to render any image.
如果 GraphQL 无论如何都返回 image
的值会发生什么?显然,我们的解析器会中断,因为它不会传递任何类型的父值.然而,此外,作为 API 的使用者,我现在必须解析 image
的内容,并以某种方式确定图像实际上是否与文章相关联,我应该对它做些什么.
What would happen if GraphQL returned a value for the image
regardless? Obviously, our resolver would break, since it would not be passed any kind of parent value. Moreover, however, as a consumer of the API, I would have to now parse the contents of image
and somehow determine whether an image was in fact associated with the article and I should do something with it.
正如您已经建议的,这里的解决方案是为 additionalInfo
指定一个解析器.您也可以在 places
解析器中简单地返回该值,即:
As you already suggested, the solution here is to specify a resolver for additionalInfo
. You can also simply return that value in your places
resolver, i.e.:
return [{name: 'Barcelona', additionalInfo: {}}]
实际上,如果架构的形状与底层数据层的形状一致,那么在处理真实数据时就不太可能遇到此类问题.
In reality, if the shape of your schema aligns with the shape of your underlying data layer, it's unlikely you'll encounter this sort of issue when working with real data.
这篇关于使用 GraphQL 触发嵌套解析器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!