正在加载,请稍候…

GraphQL API with Node.js: Apollo, DataLoader, and Subscriptions

Build production GraphQL APIs — schema, resolvers, DataLoader for N+1, subscriptions, authentication, and Pothos code-first.

GraphQL Server with Apollo Server 4

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 } }),
  },
}

DataLoader: Eliminate N+1 Queries

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)
})

// One loader per request to prevent cross-request caching
context: () => ({ loaders: { user: new DataLoader(batchFn) } })

Subscriptions

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
    },
  },
}

-> Test GraphQL responses with the JSON Viewer.