正在加载,请稍候…

使用 Node.js 构建 GraphQL API:Apollo、DataLoader 与订阅

学习构建生产级 GraphQL API,涵盖模式定义、解析器、DataLoader 解决 N+1 问题、订阅、认证以及 Pothos 代码优先方法。

使用 Node.js 构建 GraphQL API:Apollo、DataLoader 与订阅

使用 Apollo Server 4 搭建 GraphQL 服务器

const typeDefs = gql`
  type User { id: ID!; email: String!; posts: [Post!]! }
  type Post { id: ID!; title: String!; author: User! }
  type Query { users: [User!]!; user(id: ID!): User }
  type Mutation { createPost(title: String!, content: String!): Post! }
`

const resolvers = {
  Query: {
    users: () => db.user.findMany(),
    user: (_, { id }) => db.user.findUnique({ where: { id } }),
  },
  Mutation: {
    createPost: async (_, args, { user }) => {
      if (!user) throw new GraphQLError('Unauthorized', { extensions: { code: 'UNAUTHENTICATED' } })
      return db.post.create({ data: { ...args, authorId: user.id } })
    },
  },
  User: {
    posts: (user) => db.post.findMany({ where: { authorId: user.id } }),
  },
}

使用 Node.js 构建 GraphQL API:Apollo、DataLoader 与订阅 插图

DataLoader:消除 N+1 查询

const userLoader = new DataLoader(async (ids) => {
  const users = await db.user.findMany({ where: { id: { in: [...ids] } } })
  return ids.map(id => users.find(u => u.id === id) ?? null)
})

// 每个请求一个 loader,防止跨请求缓存
context: () => ({ loaders: { user: new DataLoader(batchFn) } })

使用 Node.js 构建 GraphQL API:Apollo、DataLoader 与订阅 插图

订阅

const pubsub = new PubSub()

const resolvers = {
  Subscription: {
    postCreated: { subscribe: () => pubsub.asyncIterator(['POST_CREATED']) },
  },
  Mutation: {
    createPost: async (_, args) => {
      const post = await db.post.create({ data: args })
      pubsub.publish('POST_CREATED', { postCreated: post })
      return post
    },
  },
}

-> 使用 JSON 查看器 测试 GraphQL 响应。