Apollo Server Setup
Apollo Server is the most popular GraphQL server for Node.js. It's production-ready, well-documented, and has a rich ecosystem of tools.
Let's set up a complete Apollo Server project from scratch.
Project Setup
Create a new project and install the necessary packages:
// Create project
mkdir apollo-server-demo
cd apollo-server-demo
npm init -y
// Install dependencies
npm install @apollo/server graphql
// For development
npm install -D nodemon
Apollo Server 4 has a modular design that works with any Node.js framework.
Complete Server Setup
Here's a complete server with schema, resolvers, and context:
const { ApolloServer } = require('@apollo/server');
const { startStandaloneServer } = require('@apollo/server/standalone');
// Schema
const typeDefs = `
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: [User!]!
post(id: ID!): Post
}
type Mutation {
createUser(name: String!, email: String!): User!
createPost(title: String!, content: String!, authorId: ID!): Post!
}
`;
// Sample data
const users = [
{ id: '1', name: 'Alice', email: 'alice@example.com' },
{ id: '2', name: 'Bob', email: 'bob@example.com' },
];
const posts = [
{ id: '1', title: 'First Post', content: 'Hello world!', authorId: '1' },
{ id: '2', title: 'Second Post', content: 'GraphQL is great!', authorId: '1' },
];
// Resolvers
const resolvers = {
Query: {
user: (parent, args) => users.find(u => u.id === args.id),
users: () => users,
post: (parent, args) => posts.find(p => p.id === args.id),
},
User: {
posts: (parent) => posts.filter(p => p.authorId === parent.id),
},
Post: {
author: (parent) => users.find(u => u.id === parent.authorId),
},
Mutation: {
createUser: (parent, args) => {
const user = { id: String(users.length + 1), ...args };
users.push(user);
return user;
},
createPost: (parent, args) => {
const post = { id: String(posts.length + 1), ...args };
posts.push(post);
return post;
},
},
};
// Start server
async function startServer() {
const server = new ApolloServer({ typeDefs, resolvers });
const { url } = await startStandaloneServer(server, {
listen: { port: 4000 },
});
console.log(`Server ready at ${url}`);
}
startServer();
This gives you a working GraphQL server with users and posts.
Adding Context
For real applications, add context for database connections and authentication:
const { startStandaloneServer } = require('@apollo/server/standalone');
async function startServer() {
const server = new ApolloServer({ typeDefs, resolvers });
const { url } = await startStandaloneServer(server, {
listen: { port: 4000 },
context: async ({ req }) => {
// Get token from headers
const token = req.headers.authorization || '';
// Get user from token (simplified)
const user = token ? await getUserFromToken(token) : null;
return {
user,
db: database,
};
},
});
console.log(`Server ready at ${url}`);
}
The context runs for every request and provides shared resources to all resolvers.
Production Considerations
Before going to production, consider these important settings:
const server = new ApolloServer({
typeDefs,
resolvers,
// Security settings
introspection: process.env.NODE_ENV !== 'production',
// Error handling
formatError: (formattedError, error) => {
// Don't expose internal errors in production
if (process.env.NODE_ENV === 'production') {
return { message: 'Internal server error' };
}
return formattedError;
},
// Plugins for logging, metrics, etc.
plugins: [
{
requestDidStart(requestContext) {
console.log('Request started:', requestContext.request.query);
return {
didEncounterErrors(ctx) {
console.error('Errors:', ctx.errors);
},
};
},
},
],
});
Always disable introspection in production and handle errors carefully.