GraphQL Resolver Chain实战

162 阅读1分钟

大家对于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接口分离了,从而达到了按需获取数据,按需发出请求的目的。