大家对于GraphQL resolver应该很熟悉,一个resolver定义了一个字段如何被填充数据的方法。 可是如果我们的GraphQL query变得更为复杂的时候,有一些字段是需要根据首次请求再次从后端请求数据来填充的。这些字段并不一定是每个场景之下都需要请求的。为了提升性能,我们希望只有在用户请求了某个字段的时候,才会向后端发起对应的数据请求。
举个例子
我们定义User的GraphQL类型, 其中id,name字段是通过调用/user/metaAPI来获取的, 而posts是通过调用/user/{id}/postsAPI来获取的。
type User {
id: ID!
name: String!
posts: [Post!]!
}
一种最直接的写法是
export const resolvers: Resolvers = {
Query: {
getUser: async (_, id) => {
const meta = await axios.get('/user/meta')
const posts = await axios.get(`/user/{id}/posts`)
return { ...meta, ...posts}
}
}
}
这种写法的弊端是,即使你的graphql请求里面没有指定posts字段,graphql服务也会请求/user/{id}/posts
Resolver Chain
为了解决这个问题,GraphQL里面使用了resolver chain的机制。如果一个resolver里的字段也有自己的resolver, 那么graphql会去执行那个resolver,最后汇总之后才返回数据。
示例代码
export const resolvers: Resolvers = {
Query: {
getUser: async (_, id) => {
const meta = await axios.get('/user/meta')
return meta
}
}
User: {
posts: async (user) => {
const posts = await axios.get(`/user/{id}/posts`)
return posts
}
}
}
我们为User.posts定义了自己的resolver,这样就把meta接口和posts接口分离了,从而达到了按需获取数据,按需发出请求的目的。