哪个是正确的解析器函数方法?
Which is the correct resolver function approach?
我想阐明我应该为 Apollo + GraphQL 中的解析器函数使用哪种方法
让我们假设以下架构:
type Post {
id: Int
text: String
upVotes: Int
}
type Author{
name: String
posts: [Post]
}
schema {
query: Author
}
ApoloGraphql tutorial 建议解析器映射如下:
{Query:{
author(_, args) {
return author.findAll()
}
}
},
Author {
posts: (author) => author.getPosts(),
}
据我所知,关于帖子的每一个逻辑,例如get author with posts where the count of post upVotes > args.upVotes
,必须在author
方法中处理。这为我们提供了以下解析器映射:
{Query:{
author(_, args) {
return author.findAll({
include:[model: Post]
where: {//post upVotes > args.upVotes}
})
}
},
Author {
posts: (author) => author.getPosts(),
}
调用 author
,将首先 select 在一个联合查询中有帖子的作者,其中帖子大于 args.upVotes
。然后它将再次 select 该作者的帖子,因为 Author ... getPosts()
在一个额外的查询中
从技术上讲,我可以通过删除 Author
来达到相同的结果,因为帖子已经包含在小型 author
方法中。
我有以下问题:
我需要这个声明吗?在哪些情况下?
Author {
posts: (author) => author.getPosts(),
}
如果没有,那么我如何才能知道是否请求了 posts 字段,以便
我可以有条件地包含帖子,不仅取决于
参数,还有请求的字段?
如果是,哪些帖子会包含最终结果?来自的帖子
include 语句,或 getPosts()?
您在问题中包含的解析器映射无效。我假设你对 Author
类型的意思是这样的:
Author {
posts: (author) => author.getPosts(),
}
只要您的 author
查询 总是 解析为包含 posts
属性 的对象数组,那么您正确的想法是在 Author
类型的 posts
字段中包含客户解析器是没有意义的。在这种情况下,您的查询解析器已经填充了所有必需的字段,我们无需执行任何其他操作。
GraphQL 使用默认解析器查找传递给解析器的父(或根)对象的属性,并在它们与正在解析的字段名称匹配时使用这些属性。因此,如果 GraphQL 正在解析 posts
字段,并且 posts
没有解析器,默认情况下它会查看它正在处理的 Author
对象,如果有 属性 在它的名称 posts
上,它将字段解析为它的值。
当我们提供自定义解析器时,该解析器会覆盖默认行为。因此,如果您的解析器是,例如:
posts: () => []
那么 GraphQL 将始终 return 一组空的帖子,即使 return 由 author.findAll()
编辑的对象包含帖子。
那么什么时候需要包含 posts
的解析器?
如果您的 author
解析器没有 "include" 帖子,但客户请求了该字段。正如您所说,问题是在某些情况下我们可能会进行不必要的额外调用,具体取决于您的 author
解析器是否 "includes" 帖子。你可以通过做这样的事情来解决这个问题:
posts: (author) => {
if (author.posts) return author.posts
return author.getPosts()
}
// or more succinctly
posts: author => author.posts ? author.posts : author.getPosts()
这样,我们只在确实需要获取帖子时才调用 getPosts
。或者,您可以省略 posts
解析器并在 author
解析器中处理它。我们可以查看传递给解析器的第四个参数以获取有关请求的信息,包括请求了哪些字段。例如,您的解析器可能如下所示:
author: (root, args, context, info) => {
const include = []
const requestedPosts = info.fieldNodes[0].selectionSet.selections.includes(s => s.name.value === 'posts'
if (requestedPosts) include.push(Post)
return Author.findAll({include})
}
现在,如果客户明确要求,您的解析器将只包含每位作者的帖子。提供给解析器的 AST 树对象解析起来很麻烦,但是有一些库(比如 this one)可以帮助解决这个问题。
我想阐明我应该为 Apollo + GraphQL 中的解析器函数使用哪种方法
让我们假设以下架构:
type Post {
id: Int
text: String
upVotes: Int
}
type Author{
name: String
posts: [Post]
}
schema {
query: Author
}
ApoloGraphql tutorial 建议解析器映射如下:
{Query:{
author(_, args) {
return author.findAll()
}
}
},
Author {
posts: (author) => author.getPosts(),
}
据我所知,关于帖子的每一个逻辑,例如get author with posts where the count of post upVotes > args.upVotes
,必须在author
方法中处理。这为我们提供了以下解析器映射:
{Query:{
author(_, args) {
return author.findAll({
include:[model: Post]
where: {//post upVotes > args.upVotes}
})
}
},
Author {
posts: (author) => author.getPosts(),
}
调用 author
,将首先 select 在一个联合查询中有帖子的作者,其中帖子大于 args.upVotes
。然后它将再次 select 该作者的帖子,因为 Author ... getPosts()
从技术上讲,我可以通过删除 Author
来达到相同的结果,因为帖子已经包含在小型 author
方法中。
我有以下问题:
我需要这个声明吗?在哪些情况下?
Author { posts: (author) => author.getPosts(), }
如果没有,那么我如何才能知道是否请求了 posts 字段,以便 我可以有条件地包含帖子,不仅取决于 参数,还有请求的字段?
如果是,哪些帖子会包含最终结果?来自的帖子 include 语句,或 getPosts()?
您在问题中包含的解析器映射无效。我假设你对 Author
类型的意思是这样的:
Author {
posts: (author) => author.getPosts(),
}
只要您的 author
查询 总是 解析为包含 posts
属性 的对象数组,那么您正确的想法是在 Author
类型的 posts
字段中包含客户解析器是没有意义的。在这种情况下,您的查询解析器已经填充了所有必需的字段,我们无需执行任何其他操作。
GraphQL 使用默认解析器查找传递给解析器的父(或根)对象的属性,并在它们与正在解析的字段名称匹配时使用这些属性。因此,如果 GraphQL 正在解析 posts
字段,并且 posts
没有解析器,默认情况下它会查看它正在处理的 Author
对象,如果有 属性 在它的名称 posts
上,它将字段解析为它的值。
当我们提供自定义解析器时,该解析器会覆盖默认行为。因此,如果您的解析器是,例如:
posts: () => []
那么 GraphQL 将始终 return 一组空的帖子,即使 return 由 author.findAll()
编辑的对象包含帖子。
那么什么时候需要包含 posts
的解析器?
如果您的 author
解析器没有 "include" 帖子,但客户请求了该字段。正如您所说,问题是在某些情况下我们可能会进行不必要的额外调用,具体取决于您的 author
解析器是否 "includes" 帖子。你可以通过做这样的事情来解决这个问题:
posts: (author) => {
if (author.posts) return author.posts
return author.getPosts()
}
// or more succinctly
posts: author => author.posts ? author.posts : author.getPosts()
这样,我们只在确实需要获取帖子时才调用 getPosts
。或者,您可以省略 posts
解析器并在 author
解析器中处理它。我们可以查看传递给解析器的第四个参数以获取有关请求的信息,包括请求了哪些字段。例如,您的解析器可能如下所示:
author: (root, args, context, info) => {
const include = []
const requestedPosts = info.fieldNodes[0].selectionSet.selections.includes(s => s.name.value === 'posts'
if (requestedPosts) include.push(Post)
return Author.findAll({include})
}
现在,如果客户明确要求,您的解析器将只包含每位作者的帖子。提供给解析器的 AST 树对象解析起来很麻烦,但是有一些库(比如 this one)可以帮助解决这个问题。