GraphQL in Node.js
What is GraphQL?
GraphQL is a query language for APIs that allows clients to request exactly the data they need. It provides a complete description of the data in your API.
Installation
npm install apollo-server graphqlBasic Server
const { ApolloServer, gql } = require('apollo-server');
// Type definitions
const typeDefs = gql`
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
}
type Query {
users: [User!]!
user(id: ID!): User
posts: [Post!]!
post(id: ID!): Post
}
type Mutation {
createUser(name: String!, email: String!): User!
createPost(title: String!, content: String!, authorId: ID!): Post!
}
`;
// Resolvers
const resolvers = {
Query: {
users: () => users,
user: (_, { id }) => users.find(u => u.id === id),
posts: () => posts,
post: (_, { id }) => posts.find(p => p.id === id)
},
Mutation: {
createUser: (_, { name, email }) => {
const user = { id: String(users.length + 1), name, email };
users.push(user);
return user;
},
createPost: (_, { title, content, authorId }) => {
const post = {
id: String(posts.length + 1),
title,
content,
authorId
};
posts.push(post);
return post;
}
},
User: {
posts: (user) => posts.filter(p => p.authorId === user.id)
},
Post: {
author: (post) => users.find(u => u.id === post.authorId)
}
};
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`);
});Queries
# Get all users
query {
users {
id
name
email
}
}
# Get user with posts
query {
user(id: "1") {
name
posts {
title
content
}
}
}
# Get posts with authors
query {
posts {
title
author {
name
email
}
}
}Mutations
# Create user
mutation {
createUser(name: "John Doe", email: "john@example.com") {
id
name
email
}
}
# Create post
mutation {
createPost(
title: "GraphQL Tutorial"
content: "Learn GraphQL"
authorId: "1"
) {
id
title
author {
name
}
}
}With Express
const express = require('express');
const { ApolloServer } = require('apollo-server-express');
const app = express();
const server = new ApolloServer({ typeDefs, resolvers });
await server.start();
server.applyMiddleware({ app });
app.listen(4000, () => {
console.log(`Server ready at http://localhost:4000${server.graphqlPath}`);
});Database Integration
const resolvers = {
Query: {
users: async () => {
return await User.find();
},
user: async (_, { id }) => {
return await User.findById(id);
}
},
Mutation: {
createUser: async (_, { name, email }) => {
const user = new User({ name, email });
await user.save();
return user;
},
updateUser: async (_, { id, name, email }) => {
return await User.findByIdAndUpdate(
id,
{ name, email },
{ new: true }
);
},
deleteUser: async (_, { id }) => {
await User.findByIdAndDelete(id);
return true;
}
},
User: {
posts: async (user) => {
return await Post.find({ authorId: user.id });
}
}
};Authentication
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => {
const token = req.headers.authorization || '';
const user = getUserFromToken(token);
return { user };
}
});
// In resolvers
const resolvers = {
Query: {
me: (_, __, { user }) => {
if (!user) throw new Error('Not authenticated');
return user;
}
},
Mutation: {
createPost: (_, { title, content }, { user }) => {
if (!user) throw new Error('Not authenticated');
return Post.create({ title, content, authorId: user.id });
}
}
};DataLoader (N+1 Problem)
const DataLoader = require('dataloader');
const userLoader = new DataLoader(async (userIds) => {
const users = await User.find({ _id: { $in: userIds } });
return userIds.map(id => users.find(u => u.id === id));
});
const resolvers = {
Post: {
author: (post, _, { loaders }) => {
return loaders.user.load(post.authorId);
}
}
};
const server = new ApolloServer({
typeDefs,
resolvers,
context: () => ({
loaders: {
user: userLoader
}
})
});Subscriptions
const { PubSub } = require('graphql-subscriptions');
const pubsub = new PubSub();
const typeDefs = gql`
type Subscription {
postAdded: Post!
}
`;
const resolvers = {
Mutation: {
createPost: async (_, { title, content }) => {
const post = await Post.create({ title, content });
pubsub.publish('POST_ADDED', { postAdded: post });
return post;
}
},
Subscription: {
postAdded: {
subscribe: () => pubsub.asyncIterator(['POST_ADDED'])
}
}
};Best Practices
- Use DataLoader to prevent N+1 queries
- Implement authentication in context
- Validate inputs
- Limit query depth
- Use subscriptions for real-time
- Cache responses
Interview Tips
- Explain GraphQL: Query language for APIs
- Show schema: Type definitions and resolvers
- Demonstrate queries: Flexible data fetching
- Discuss mutations: Data modifications
- Mention DataLoader: Solve N+1 problem
- Show subscriptions: Real-time updates
Summary
GraphQL is a query language allowing clients to request specific data. Define schema with type definitions, implement resolvers for data fetching. Use DataLoader to prevent N+1 queries, context for authentication, subscriptions for real-time updates.
Test Your Knowledge
Take a quick quiz to test your understanding of this topic.