In the evolving landscape of API development, GraphQL has emerged as a powerful alternative to traditional REST APIs. It allows clients to request exactly the data they need, no more and no less, solving common problems like over-fetching and under-fetching. When building GraphQL servers with Node.js, **Apollo Server** is a popular, production-ready choice that simplifies the process significantly. This guide will walk you through setting up a basic GraphQL server using Node.js and Apollo Server, covering schema definition, resolvers, and integration with Express.js.
Why GraphQL?
- Efficient Data Fetching: Clients request only what they need, reducing network payload.
- Single Endpoint: All requests go to a single endpoint, simplifying API management.
- Strongly Typed Schema: Provides a clear contract between client and server, enabling better tooling and validation.
- Reduced Round Trips: Fetch related data in a single request, avoiding multiple API calls.
- Evolving APIs: Easily add new fields and types to your API without breaking existing clients.
Prerequisites
- Node.js and npm (or yarn) installed.
- Basic understanding of JavaScript and Node.js.
- Familiarity with Express.js concepts (optional but helpful).
1. Project Setup
Start by creating a new Node.js project and installing the necessary packages:
# Create a new project directory
mkdir my-graphql-server
cd my-graphql-server
# Initialize npm project
npm init -y
# Install dependencies
npm install express @apollo/server graphql
- `express`: Our web framework for Node.js.
- `@apollo/server`: The core Apollo Server library.
- `graphql`: The reference implementation of GraphQL, required by Apollo Server.
2. Define Your GraphQL Schema (Type Definitions)
The schema defines the structure of your data and the operations clients can perform. GraphQL uses its own Schema Definition Language (SDL). Create a file named `schema.js` (or `typeDefs.js`).
// schema.js
const { gql } = require('apollo-server-express'); // Or from '@apollo/server' if not using express-specific integration
// Define your GraphQL schema using GraphQL SDL
const typeDefs = gql`
# Define a 'Book' type
type Book {
id: ID!
title: String!
author: String!
year: Int
}
# Define the Query type (for reading data)
type Query {
books: [Book] # Get a list of all books
book(id: ID!): Book # Get a single book by ID
}
# Define the Mutation type (for writing/modifying data)
type Mutation {
addBook(title: String!, author: String!, year: Int): Book
updateBook(id: ID!, title: String, author: String, year: Int): Book
deleteBook(id: ID!): String
}
`;
module.exports = typeDefs;
3. Implement Resolvers
Resolvers are functions that tell GraphQL how to fetch the data for a particular type or field in your schema. They map the schema fields to actual data sources (e.g., databases, external APIs, or in-memory data). Create a file named `resolvers.js`.
// resolvers.js
// In-memory data for demonstration (replace with database calls in a real app)
let books = [
{ id: '1', title: 'The Great Gatsby', author: 'F. Scott Fitzgerald', year: 1925 },
{ id: '2', title: 'To Kill a Mockingbird', author: 'Harper Lee', year: 1960 },
];
const resolvers = {
Query: {
books: () => books, // Returns all books
book: (parent, { id }) => books.find(book => book.id === id), // Finds a book by ID
},
Mutation: {
addBook: (parent, { title, author, year }) => {
const newBook = { id: String(books.length + 1), title, author, year };
books.push(newBook);
return newBook;
},
updateBook: (parent, { id, title, author, year }) => {
const bookIndex = books.findIndex(book => book.id === id);
if (bookIndex === -1) return null; // Book not found
const updatedBook = { ...books[bookIndex], title, author, year };
books[bookIndex] = updatedBook;
return updatedBook;
},
deleteBook: (parent, { id }) => {
const initialLength = books.length;
books = books.filter(book => book.id !== id);
if (books.length < initialLength) {
return `Book with ID ${id} deleted successfully.`;
}
return `Book with ID ${id} not found.`;
},
},
};
module.exports = resolvers;
4. Set Up Apollo Server with Express.js
Now, let's create our main server file, `server.js`, and integrate Apollo Server with Express.
// server.js
const express = require('express');
const { ApolloServer } = require('@apollo/server');
const { expressMiddleware } = require('@apollo/server/express4');
const { ApolloServerPluginDrainHttpServer } = require('@apollo/server/plugin/drainHttpServer');
const http = require('http');
const cors = require('cors');
const typeDefs = require('./schema');
const resolvers = require('./resolvers');
async function startApolloServer() {
const app = express();
const httpServer = http.createServer(app);
// Set up Apollo Server
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
});
await server.start();
// Apply Apollo Server middleware to Express
app.use(
'/graphql', // The path where your GraphQL API will be accessible
cors(),
express.json(),
expressMiddleware(server),
);
// Start the HTTP server
const PORT = process.env.PORT || 4000;
await new Promise((resolve) => httpServer.listen({ port: PORT }, resolve));
console.log(`🚀 Server ready at http://localhost:${PORT}/graphql`);
}
startApolloServer();
5. Running Your GraphQL Server
To start your server, run:
node server.js
You should see "🚀 Server ready at http://localhost:4000/graphql" in your console.
6. Testing Your API with Apollo Sandbox/Playground
Open your browser and navigate to `http://localhost:4000/graphql`. You will be greeted by Apollo Sandbox (or GraphQL Playground), a powerful in-browser IDE for interacting with your GraphQL API.
Example Queries:
# Get all books
query {
books {
id
title
author
year
}
}
# Get a single book by ID
query {
book(id: "1") {
title
author
}
}
# Add a new book
mutation {
addBook(title: "The Hobbit", author: "J.R.R. Tolkien", year: 1937) {
id
title
author
}
}
# Update a book
mutation {
updateBook(id: "1", title: "The Great Gatsby (Revised)", year: 2023) {
title
year
}
}
# Delete a book
mutation {
deleteBook(id: "2")
}
You've successfully set up a basic GraphQL server using Node.js and Apollo Server! This foundation allows you to build highly efficient and flexible APIs where clients have precise control over the data they receive. From here, you can expand your schema, integrate with databases (like MongoDB or PostgreSQL), implement authentication and authorization, and explore advanced features like subscriptions for real-time capabilities. GraphQL, combined with Apollo Server, provides a robust and developer-friendly ecosystem for modern API development.