GraphQL with Node.js

In this chapter, we will explore GraphQL with Node.js in detail. GraphQL is a powerful query language for APIs and a runtime for executing those queries by using a type system that you define for your data. It provides an alternative to RESTful APIs and offers more flexibility and efficiency in how clients request data.

Bonus💡: Practical example at the end of article

What is GraphQL?

GraphQL is a query language for your API, and a server-side runtime for executing queries by using a type system that you define for your data. Unlike REST, which requires loading data from multiple endpoints, GraphQL allows clients to request exactly the data they need, all in one go.

Key Features of GraphQL:

  • Single Endpoint: Unlike REST, which has multiple endpoints, GraphQL uses a single endpoint to handle all requests.
  • Strongly Typed Schema: GraphQL APIs are organized around types and fields, not endpoints.
  • Precise Data Fetching: Clients can ask for specific data, which reduces over-fetching and under-fetching.
  • Introspection: GraphQL APIs are self-documenting, allowing clients to understand the API by querying it.

Why Use GraphQL?

GraphQL is favored over REST in many scenarios because it:

  • Reduces API Overheads: Only the necessary data is fetched, reducing the amount of data transferred over the network.
  • Single Request: Clients can fetch related data in a single request.
  • Versionless API: With GraphQL, you can deprecate fields without impacting clients using other parts of the API.
  • Better Developer Experience: With introspection and a strongly typed schema, developers can explore and understand the API without needing additional documentation.

Setting Up a GraphQL Server with Node.js

Project Initialization

We will create a simple GraphQL server using Node.js and Express.

1 Create a new Node.js project:

				
					mkdir graphql-nodejs
cd graphql-nodejs
npm init -y

				
			

2.Install Required Packages: Install express, express-graphql, and graphql:

				
					npm install express express-graphql graphql

				
			

3.Project Structure:

				
					graphql-nodejs/
├── index.js
├── schema.js
└── package.json

				
			

Creating the Schema

The schema defines the structure of the API and the types of data that can be queried.

File: schema.js

				
					// File: schema.js

const { buildSchema } = require('graphql');

// Define the schema
const schema = buildSchema(`
  type Query {
    hello: String
    user(id: Int!): User
    users: [User]
  }

  type Mutation {
    createUser(name: String!, age: Int!): User
  }

  type User {
    id: Int
    name: String
    age: Int
  }
`);

let users = [
  { id: 1, name: 'John Doe', age: 28 },
  { id: 2, name: 'Jane Doe', age: 25 }
];

// Define resolvers
const root = {
  hello: () => 'Hello, world!',
  user: ({ id }) => users.find(user => user.id === id),
  users: () => users,
  createUser: ({ name, age }) => {
    const newUser = { id: users.length + 1, name, age };
    users.push(newUser);
    return newUser;
  }
};

module.exports = { schema, root };

				
			

Here, we define a simple schema with a Query type to fetch data and a Mutation type to modify data. We also define a User type, which represents the data structure of a user.

Setting Up the Server

File: index.js

				
					// File: index.js

const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, root } = require('./schema');

const app = express();

app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,  // Enables the GraphiQL tool
}));

const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}/graphql`);
});

				
			

Here, we set up an Express server and use the express-graphql middleware to handle requests to the /graphql endpoint. We also enable GraphiQL, a graphical interface for making GraphQL queries.

Querying Data with GraphQL

GraphQL queries are how clients ask for data from the server. In this section, we’ll look at how to write queries to fetch data.

Basic Queries

With the server running, navigate to http://localhost:4000/graphql to open the GraphiQL interface.

  1. Simple Query:

				
					{
  hello
}

				
			
				
					// Output 
{
  "data": {
    "hello": "Hello, world!"
  }
}

				
			

2.Querying a Single User:

				
					{
  user(id: 1) {
    name
    age
  }
}

				
			
				
					// Output 
{
  "data": {
    "user": {
      "name": "John Doe",
      "age": 28
    }
  }
}

				
			

3.Querying Multiple Users:

				
					{
  users {
    id
    name
    age
  }
}

				
			
				
					// Output 
{
  "data": {
    "users": [
      {
        "id": 1,
        "name": "John Doe",
        "age": 28
      },
      {
        "id": 2,
        "name": "Jane Doe",
        "age": 25
      }
    ]
  }
}


				
			

Mutating Data with GraphQL

Mutations in GraphQL are used to modify data on the server (similar to POST, PUT, DELETE in REST).

Basic Mutations

  1. Creating a New User:

				
					mutation {
  createUser(name: "Alice", age: 30) {
    id
    name
    age
  }
}

				
			
				
					// Output 
{
  "data": {
    "createUser": {
      "id": 3,
      "name": "Alice",
      "age": 30
    }
  }
}

				
			

2.Fetching All Users After Mutation:

				
					{
  users {
    id
    name
    age
  }
}

				
			
				
					// Output 
{
  "data": {
    "users": [
      {
        "id": 1,
        "name": "John Doe",
        "age": 28
      },
      {
        "id": 2,
        "name": "Jane Doe",
        "age": 25
      },
      {
        "id": 3,
        "name": "Alice",
        "age": 30
      }
    ]
  }
}


				
			

Advanced Concepts

Input Types

In complex GraphQL mutations, you might need to pass multiple arguments. GraphQL allows you to define input types to structure these arguments.

				
					// Extend the schema.js

const schema = buildSchema(`
  input UserInput {
    name: String!
    age: Int!
  }

  type Query {
    users: [User]
  }

  type Mutation {
    createUser(input: UserInput): User
  }

  type User {
    id: Int
    name: String
    age: Int
  }
`);

				
			

Example Mutation with Input Type:

				
					mutation {
  createUser(input: { name: "Bob", age: 22 }) {
    id
    name
    age
  }
}

				
			
				
					// Output
{
  "data": {
    "createUser": {
      "id": 4,
      "name": "Bob",
      "age": 22
    }
  }
}

				
			

Aliases and Fragments

GraphQL allows the use of aliases to rename the result of a query or fragments to reuse parts of queries.

Using Aliases:

				
					{
  john: user(id: 1) {
    name
  }
  jane: user(id: 2) {
    name
  }
}

				
			
				
					// Output 
{
  "data": {
    "john": {
      "name": "John Doe"
    },
    "jane": {
      "name": "Jane Doe"
    }
  }
}

				
			

Using Fragments

				
					{
  users {
    ...userFields
  }
}

fragment userFields on User {
  id
  name
  age
}

				
			
				
					// Output 
{
  "data": {
    "users": [
      {
        "id": 1,
        "name": "John Doe",
        "age": 28
      },
      {
        "id": 2,
        "name": "Jane Doe",
        "age": 25
      }
    ]
  }
}

				
			

Authentication and Authorization

In real-world applications, you need to protect certain parts of your GraphQL API. This can be done by implementing authentication and authorization.

Protecting Resolvers

1 Middleware Function for Authentication:

				
					// Add to schema.js or index.js

const authenticate = (resolver) => {
  return (parent, args, context, info) => {
    if (!context.isAuthenticated) {
      throw new Error('Not Authenticated');
    }
    return resolver(parent, args, context, info);
  };
};

				
			

2.Applying Middleware to Resolvers:

				
					// Apply middleware to a resolver
const root = {
  users: authenticate(() => users)
};

				
			

3.Passing Context:

				
					// In index.js
app.use('/graphql', graphqlHTTP((req) => ({
  schema: schema,
  rootValue: root,
  context: {
    isAuthenticated: req.headers.authorization === 'Bearer mysecrettoken'
  },
  graphiql: true,
})));

				
			

Practical example : BookStore

Let’s build a practical example of using GraphQL with Node.js by creating a simple Bookstore API. This API will allow us to perform operations like adding books, retrieving books, and managing authors. We’ll cover setting up the project, creating the GraphQL schema, writing queries and mutations, and testing the API.

Operations:

  • Add a book.
  • Retrieve all books.
  • Retrieve a book by ID.
  • Add an author.
  • Retrieve all authors.

Entities:

  • Book: Represents a book with fields like title, author, and publication year.
  • Author: Represents an author with fields like name and age.

Setting Up the Project

1.Initialize the Project:

				
					mkdir bookstore-graphql
cd bookstore-graphql
npm init -y

				
			

2.Install Required Packages: Install express, express-graphql, and graphql:

				
					npm install express express-graphql graphql

				
			

3.Project Structure:

				
					bookstore-graphql/
├── index.js
├── schema.js
├── data.js
└── package.json

				
			

Data Management

We’ll create a simple in-memory data store to manage our books and authors.

File: data.js

				
					// File: data.js

const books = [
  { id: 1, title: '1984', authorId: 1, year: 1949 },
  { id: 2, title: 'Brave New World', authorId: 2, year: 1932 }
];

const authors = [
  { id: 1, name: 'George Orwell', age: 46 },
  { id: 2, name: 'Aldous Huxley', age: 69 }
];

module.exports = { books, authors };

				
			

This file exports two arrays, books and authors, which will act as our in-memory data store.

Creating the GraphQL Schema

Next, we’ll define our GraphQL schema, including types, queries, and mutations.

File: schema.js

				
					// File: schema.js

const { buildSchema } = require('graphql');
const { books, authors } = require('./data');

// Define the GraphQL schema
const schema = buildSchema(`
  type Query {
    book(id: Int!): Book
    books: [Book]
    author(id: Int!): Author
    authors: [Author]
  }

  type Mutation {
    addBook(title: String!, authorId: Int!, year: Int!): Book
    addAuthor(name: String!, age: Int!): Author
  }

  type Book {
    id: Int
    title: String
    author: Author
    year: Int
  }

  type Author {
    id: Int
    name: String
    age: Int
    books: [Book]
  }
`);

// Define the resolvers
const root = {
  book: ({ id }) => books.find(book => book.id === id),
  books: () => books,
  author: ({ id }) => authors.find(author => author.id === id),
  authors: () => authors,
  
  addBook: ({ title, authorId, year }) => {
    const newBook = { id: books.length + 1, title, authorId, year };
    books.push(newBook);
    return newBook;
  },
  
  addAuthor: ({ name, age }) => {
    const newAuthor = { id: authors.length + 1, name, age };
    authors.push(newAuthor);
    return newAuthor;
  }
};

module.exports = { schema, root };

				
			

In this schema:

  • The Query type defines the possible queries, such as fetching books and authors.
  • The Mutation type allows us to add new books and authors.
  • The Book type has a title, author, and year.
  • The Author type has a name, age, and a list of books.

Setting Up the Server

Now, we’ll set up the Express server and integrate the GraphQL middleware.

File: index.js

				
					// File: index.js

const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { schema, root } = require('./schema');

const app = express();

app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,  // Enable GraphiQL UI
}));

const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}/graphql`);
});

				
			

This sets up a basic Express server that listens on port 4000 and uses the /graphql endpoint to handle GraphQL requests. The GraphiQL UI is enabled for easy testing.

Running the Application

Start the Server:

				
					node index.js

				
			

Access the GraphQL Playground: Open your browser and go to http://localhost:4000/graphql. Here you can run queries and mutations using the GraphiQL interface.

Writing and Executing Queries

Fetch All Books

				
					{
  books {
    id
    title
    year
    author {
      name
      age
    }
  }
}

				
			
				
					// Output 
{
  "data": {
    "books": [
      {
        "id": 1,
        "title": "1984",
        "year": 1949,
        "author": {
          "name": "George Orwell",
          "age": 46
        }
      },
      {
        "id": 2,
        "title": "Brave New World",
        "year": 1932,
        "author": {
          "name": "Aldous Huxley",
          "age": 69
        }
      }
    ]
  }
}

				
			

Fetch a Single Book by ID

				
					{
  book(id: 1) {
    title
    year
    author {
      name
      age
    }
  }
}

				
			
				
					// Output 
{
  "data": {
    "book": {
      "title": "1984",
      "year": 1949,
      "author": {
        "name": "George Orwell",
        "age": 46
      }
    }
  }
}

				
			

Fetch All Authors

				
					{
  authors {
    id
    name
    age
    books {
      title
    }
  }
}

				
			
				
					// Output 
{
  "data": {
    "authors": [
      {
        "id": 1,
        "name": "George Orwell",
        "age": 46,
        "books": [
          {
            "title": "1984"
          }
        ]
      },
      {
        "id": 2,
        "name": "Aldous Huxley",
        "age": 69,
        "books": [
          {
            "title": "Brave New World"
          }
        ]
      }
    ]
  }
}

				
			

Writing and Executing Mutations

Add a New Book

				
					mutation {
  addBook(title: "To Kill a Mockingbird", authorId: 1, year: 1960) {
    id
    title
    year
    author {
      name
    }
  }
}

				
			
				
					// Output 
{
  "data": {
    "addBook": {
      "id": 3,
      "title": "To Kill a Mockingbird",
      "year": 1960,
      "author": {
        "name": "George Orwell"
      }
    }
  }
}

				
			

Add a New Author

				
					mutation {
  addAuthor(name: "Harper Lee", age: 89) {
    id
    name
    age
  }
}

				
			
				
					// Output 
{
  "data": {
    "addAuthor": {
      "id": 3,
      "name": "Harper Lee",
      "age": 89
    }
  }
}


				
			

Testing the API

After adding the new book and author, you can re-run the books and authors queries to see the updated data.

This practical example demonstrated how to create a simple Bookstore API using GraphQL with Node.js. We covered:

  • Setting up a Node.js project and installing necessary packages.
  • Creating a GraphQL schema with types, queries, and mutations.
  • Building an Express server to handle GraphQL requests.
  • Writing and executing queries and mutations to interact with the API.

This chapter has walked you through the fundamentals of GraphQL with Node.js, from setting up a simple server to advanced topics like input types, fragments, and authorization. With GraphQL, you can build flexible, efficient, and scalable APIs that empower clients to request exactly the data they need, in the shape they need it.Happy coding !❤️

Table of Contents

Contact here

Copyright © 2025 Diginode

Made with ❤️ in India