Loading lesson path
Concept visual
Start from A
GraphQL is a query language for APIs and a runtime for executing those queries against your data. It was developed by Facebook in 2012 and publicly released in 2015.
: Request exactly what you need, nothing more
: Access all resources through one endpoint
: Clear schema defines available data and operations
: Queries match the shape of your data
: Schema serves as documentation
Unlike REST, GraphQL lets clients specify exactly what data they need, reducing over-fetching and under-fetching of data. Getting Started with GraphQL in Node.js
Node.js installed (v14 or later recommended) Basic knowledge of JavaScript and Node.js npm or yarn package manager
Create a new directory and initialize a Node.js project:
Formula
mkdir graphql - server cd graphql - server npm init - yFormula
npm install express express - graphql graphqlexpress
Formula
: Web framework for Node.js express - graphql: Middleware for creating a GraphQL HTTP server graphql : The JavaScript reference implementation of GraphQL
3.1 Define Your Data Model Create a new file server.js and start by defining your data model using GraphQL's Schema Definition Language (SDL):
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { buildSchema } = require('graphql');
// Sample data const books = [
{
id: '1', title: 'The Great Gatsby', author: 'F. Scott Fitzgerald', year: 1925, genre: 'Novel'
},
{
id: '2', title: 'To Kill a Mockingbird', author: 'Harper Lee', year: 1960, genre: 'Southern Gothic'
}
];3.2 Define the GraphQL Schema Add the schema definition to your server.js file:
// Define the schema using GraphQL schema language const schema = buildSchema(`
# A book has a title, author, and publication year type Book {id: ID! title: String! author: String! year: Int genre: String
}
# The "Query" type is the root of all GraphQL queries type Query {
# Get all books books: [Book!]!# Get a specific book by ID book(id: ID!): Book # Search books by title or author searchBooks(query: String!): [Book!]!
}
`);3.3 Implement Resolvers Add resolver functions to fetch the actual data:
// Define resolvers for the schema fields const root = {
// Resolver for fetching all books books: () => books,// Resolver for fetching a single book by ID
book: ({ id }) => books.find(book => book.id === id),
// Resolver for searching books searchBooks: ({ query }) => {
const searchTerm = query.toLowerCase();
return books.filter(
book =>
book.title.toLowerCase().includes(searchTerm) ||
book.author.toLowerCase().includes(searchTerm)
);
}
};3.4 Set Up the Express Server
// Create an Express app const app = express();
// Set up the GraphQL endpoint app.use('/graphql', graphqlHTTP({schema: schema, rootValue: root, // Enable the GraphiQL interface for testing graphiql: true,
}));
// Start the server const PORT = 4000;
app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}/graphql`);
});Step 4: Run and Test Your GraphQL Server 4.1 Start the Server Run your server with Node.js: node server.js
4.2 Test with GraphiQL
Formula
Open your browser and navigate to http://localhost:4000/graphql to access the GraphiQL interface.{
books {id title author year
}
}{
book(id: "1") {title author genre
}
}{
searchBooks(query: "Gatsby") {title author year
}
}Mutations are used to modify data on the server. Let's add the ability to add, update, and delete books.
const schema = buildSchema(`
# ... (previous types remain the same) ...
# Input type for adding/updating books input BookInput {title: String author: String year: Int genre: String
}
type Mutation {
# Add a new book addBook(input: BookInput!): Book!
# Update an existing book updateBook(id: ID!, input: BookInput!): Book
# Delete a book deleteBook(id: ID!): Boolean
}
`);const root = {
// ... (previous query resolvers remain the same) ...
// Mutation resolvers addBook: ({ input }) => {
const newBook = {Formula
id: String(books.length + 1),...input}
books.push(newBook);
return newBook;
}, updateBook: ({ id, input }) => {
const bookIndex = books.findIndex(book => book.id === id);
if (bookIndex === -1) return null;
const updatedBook = {...books[bookIndex],...input
}
books[bookIndex] = updatedBook;
return updatedBook;
}, deleteBook: ({ id }) => {
const bookIndex = books.findIndex(book => book.id === id);
if (bookIndex === -1) return false;
books.splice(bookIndex, 1);
return true;
}
};Add a New Book mutation {
addBook(input: {
title: "1984"
author: "George Orwell"
year: 1949 genre: "Dystopian"
}) {id title author
}
}
Update a Book mutation {
updateBook(
id: "1"
input: { year: 1926 }
) {title year
}
}
Delete a Book mutation {
deleteBook(id: "2")
}const root = {
book: ({ id }) => {
const book = books.find(book => book.id === id);
if (!book) {
throw new Error('Book not found');
}
return book;
},// ... other resolvers
}const { GraphQLError } = require('graphql');
const root = {
addBook: ({ input }) => {
if (input.year && (input.year < 0 || input.year > new Date().getFullYear() + 1)) {
throw new GraphQLError('Invalid publication year', {
extensions: { code: 'BAD_USER_INPUT' }
}
}// ... rest of the resolver
}
};Formula
3. N + 1 ProblemUse DataLoader to batch and cache database queries:
npm install dataloader const DataLoader = require('dataloader');
// Create a loader for books const bookLoader = new DataLoader(async (ids) => {
// This would be a database query in a real app return ids.map(id => books.find(book => book.id === id));
});
const root = {
book: ({ id }) => bookLoader.load(id),// ... other resolvers
};Connect to a real database (MongoDB, PostgreSQL, etc.)