| name | graphql |
| description | Build GraphQL APIs with Node.js using Apollo Server, type definitions, resolvers, and real-time subscriptions |
| version | 2.1.0 |
| sasmp_version | 1.3.0 |
| bonded_agent | 02-express-framework |
| bond_type | PRIMARY_BOND |
GraphQL with Node.js Skill
Master building flexible, efficient GraphQL APIs using Node.js with Apollo Server, type-safe schemas, and real-time subscriptions.
Quick Start
GraphQL API in 4 steps:
- Define Schema - Types, queries, mutations
- Write Resolvers - Data fetching logic
- Setup Server - Apollo Server configuration
- Connect Data - Database integration
Core Concepts
Schema Definition (SDL)
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String
author: User!
}
type Query {
user(id: ID!): User
users(limit: Int, offset: Int): [User!]!
post(id: ID!): Post
}
type Mutation {
createUser(input: CreateUserInput!): User!
updateUser(id: ID!, input: UpdateUserInput!): User
deleteUser(id: ID!): Boolean!
}
input CreateUserInput {
name: String!
email: String!
password: String!
}
type Subscription {
postCreated: Post!
}
Apollo Server Setup
const { ApolloServer } = require('@apollo/server');
const { expressMiddleware } = require('@apollo/server/express4');
const { readFileSync } = require('fs');
const typeDefs = readFileSync('./schema.graphql', 'utf-8');
const resolvers = {
Query: {
user: async (_, { id }, { dataSources }) => {
return dataSources.userAPI.getUser(id);
},
users: async (_, { limit = 10, offset = 0 }, { dataSources }) => {
return dataSources.userAPI.getUsers(limit, offset);
}
},
Mutation: {
createUser: async (_, { input }, { dataSources }) => {
return dataSources.userAPI.createUser(input);
}
},
User: {
posts: async (parent, _, { dataSources }) => {
return dataSources.postAPI.getPostsByAuthor(parent.id);
}
}
};
const server = new ApolloServer({ typeDefs, resolvers });
await server.start();
app.use('/graphql', express.json(), expressMiddleware(server, {
context: async ({ req }) => ({
user: req.user,
dataSources: {
userAPI: new UserAPI(),
postAPI: new PostAPI()
}
})
}));
Learning Path
Beginner (2-3 weeks)
- ✅ Understand GraphQL concepts
- ✅ Define schemas with SDL
- ✅ Write basic resolvers
- ✅ Query and mutation basics
Intermediate (4-6 weeks)
- ✅ Field resolvers and relationships
- ✅ Input validation
- ✅ Error handling
- ✅ DataLoader for N+1
Advanced (8-10 weeks)
- ✅ Subscriptions (real-time)
- ✅ Authentication and authorization
- ✅ Federation for microservices
- ✅ Performance optimization
DataLoader for N+1 Problem
const DataLoader = require('dataloader');
const createUserLoader = () =>
new DataLoader(async (userIds) => {
const users = await User.find({ _id: { $in: userIds } });
const userMap = new Map(users.map(u => [u.id, u]));
return userIds.map(id => userMap.get(id));
});
// Use in resolver
User: {
posts: (parent, _, { loaders }) => {
return loaders.userLoader.load(parent.authorId);
}
}
Authentication & Authorization
const { shield, rule, allow } = require('graphql-shield');
const isAuthenticated = rule()((parent, args, { user }) => {
return user !== null;
});
const isAdmin = rule()((parent, args, { user }) => {
return user?.role === 'admin';
});
const permissions = shield({
Query: { '*': allow, users: isAuthenticated },
Mutation: {
createPost: isAuthenticated,
deleteUser: isAdmin
}
});
Error Handling
const { ApolloError, UserInputError } = require('apollo-server-express');
class NotFoundError extends ApolloError {
constructor(message) {
super(message, 'NOT_FOUND');
}
}
// In resolvers
const resolvers = {
Query: {
user: async (_, { id }) => {
const user = await User.findById(id);
if (!user) throw new NotFoundError(`User ${id} not found`);
return user;
}
}
};
Unit Test Template
const { createTestClient } = require('apollo-server-testing');
describe('GraphQL API', () => {
let query, mutate;
beforeAll(() => {
const server = new ApolloServer({ typeDefs, resolvers });
const testClient = createTestClient(server);
query = testClient.query;
mutate = testClient.mutate;
});
it('should return users list', async () => {
const GET_USERS = `query { users { id name } }`;
const res = await query({ query: GET_USERS });
expect(res.errors).toBeUndefined();
expect(res.data.users).toBeDefined();
});
});
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| N+1 query issue | Field resolvers | Use DataLoader |
| Slow queries | No caching | Implement Apollo Cache |
| Type errors | Schema mismatch | Validate with codegen |
| Auth bypass | Missing guards | Use graphql-shield |
When to Use
Use GraphQL when:
- Clients need flexible data fetching
- Multiple clients with different data needs
- Avoiding over-fetching/under-fetching
- Real-time updates needed
- API evolution without versioning
Related Skills
- Express REST API (alternative approach)
- Database Integration (data sources)
- JWT Authentication (securing API)