Introduction to GraphQL with Node.js
In the world of APIs, REST has been the standard for a long time.
However, as applications became more complex and had multiple clients (web, mobile, etc.), challenges arose such as over-fetching (getting more data than needed) and under-fetching (having to make multiple requests to get all the necessary data).
To address these issues, Facebook created and released GraphQL in 2015 as an alternative for designing APIs. In this lesson, we will explore what GraphQL is and how we can start using it with Node.js.
What is GraphQL?
GraphQL is a query language for APIs and a runtime for executing those queries with your data.
It differs from REST in its approach: instead of having multiple endpoints that return fixed data structures, a GraphQL API exposes a single endpoint to which clients send queries that specify exactly what data they need.
Key principles of GraphQL:
- Declarative Query: Clients ask for exactly what they need and nothing more, solving over-fetching.
- Single Endpoint: All operations are performed through a single URL, simplifying client management.
- Strong Type System: The GraphQL API is defined by a strongly typed schema, which provides automatic data validation and enables powerful tools.
- Introspection: Clients can query the API's schema to understand what data is available and how to query it.
---
Key Components of GraphQL
- Schema: This is the core of any GraphQL API. It defines all available data types, their relationships, and the operations clients can perform (queries, mutations, subscriptions). It is written in GraphQL's Schema Definition Language (SDL).
type Book { id: ID! title: String! author: Author! year: Int } type Author { id: ID! name: String! books: [Book!]! } type Query { books: [Book!]! book(id: ID!): Book authors: [Author!]! } type Mutation { addBook(title: String!, authorId: ID!, year: Int): Book updateBook(id: ID!, title: String, year: Int): Book }
- Queries: Used to fetch data from the server. Clients specify exactly which fields they need from a resource.
query GetBookAndAuthor { book(id: "1") { title author { name } } }
- Mutations: Used to modify data on the server (create, update, delete). They are the equivalent of REST's POST, PUT, DELETE methods.
mutation AddNewBook { addBook(title: "Don Quixote", authorId: "101", year: 1605) { id title author { name } } }
- Resolvers: These are functions that tell GraphQL how to fetch the data for a specific type or field in the schema. When a client sends a query, GraphQL calls the corresponding resolvers to build the response.
---
GraphQL with Node.js and Apollo Server
To build a GraphQL API with Node.js, the most popular and robust library is Apollo Server. It provides a complete implementation of a GraphQL server that integrates easily with frameworks like Express.js.
Getting Started:
- Initialize a Node.js project and install packages:
- Create a basic GraphQL server (
index.js
): - Run the application:
- Test the GraphQL API:
mkdir my-graphql-api
cd my-graphql-api
npm init -y
npm install express @apollo/server graphql
const { ApolloServer } = require('@apollo/server');
const { expressMiddleware } = require('@apollo/server/express4');
const express = require('express');
const http = require('http');
const cors = require('cors'); // To allow requests from the frontend
// 1. Define the schema (Schema Definition Language - SDL)
const typeDefs = `
type Book {
id: ID!
title: String!
author: String!
}
type Query {
books: [Book!]!
book(id: ID!): Book
}
type Mutation {
addBook(title: String!, author: String!): Book
}
`;
// Example data (simulating a database)
let books = [
{
id: '1',
title: 'The Great Gatsby',
author: 'F. Scott Fitzgerald',
},
{
id: '2',
title: 'To Kill a Mockingbird',
author: 'Harper Lee',
},
];
// 2. Define the Resolvers
const resolvers = {
Query: {
books: () => books,
book: (parent, args) => books.find(book => book.id === args.id),
},
Mutation: {
addBook: (parent, args) => {
const newBook = {
id: String(books.length + 1), // Simple ID generation
title: args.title,
author: args.author,
};
books.push(newBook);
return newBook;
},
},
};
async function startApolloServer() {
const app = express();
const httpServer = http.createServer(app);
// 3. Create an instance of ApolloServer
const server = new ApolloServer({
typeDefs,
resolvers,
});
// Start the Apollo server
await server.start();
// Apply the Express middleware for GraphQL
app.use(
'/graphql', // The endpoint where your GraphQL API will be available
cors(),
express.json(),
expressMiddleware(server),
);
// Start the HTTP server
await new Promise((resolve) => httpServer.listen({ port: 4000 }, resolve));
console.log(`🚀 GraphQL server ready at http://localhost:4000/graphql`);
}
startApolloServer();
node index.js
Once the server is running, you can access the Apollo Sandbox interface (or GraphQL Playground if using older versions) by navigating to http://localhost:4000/graphql
in your browser. There, you can test your queries and mutations:
# Query to get all books
query {
books {
id
title
author
}
}
# Mutation to add a book
mutation {
addBook(title: "1984", author: "George Orwell") {
id
title
}
}
GraphQL offers tremendous flexibility for clients, allowing them to request only the data they truly need. If your application has diverse clients or complex data requirements, GraphQL with Node.js and Apollo Server can be a powerful alternative to traditional REST APIs.