Table of Contents

Traditional REST APIs often come with challenges like over-fetching and under-fetching data. Enter GraphQL, a modern solution that’s transforming how APIs are built and consumed. In this guide, you’ll learn step-by-step how to create a GraphQL API using Node.js. Whether you’re new to GraphQL or looking to solidify your basics, this guide will help you understand every step, including middleware integration, to build scalable and efficient APIs.

What is GraphQL?

GraphQL is a query language for your API and a runtime for executing those queries. Unlike REST, it allows clients to request only the data they need.

Key Advantages:

  • Avoids over-fetching and under-fetching.
  • Single endpoint for all operations.
  • Strongly typed schema ensures better error handling.

Real-World Applications: Companies like Facebook, GitHub, and Shopify use GraphQL to handle complex data requirements efficiently.

Understanding the Basics of GraphQL Queries and Mutations

GraphQL revolves around two main operations: queries and mutations. These operations help you fetch or modify data in your GraphQL API.

  • Queries are used to fetch data. They allow clients to specify exactly what data they need, preventing over-fetching (getting too much data) or under-fetching (not getting enough data).For example, the query below fetches a list of books with just the title and author:graphqlCopyEditquery { books { title author } } Explanation:
    • query: This tells GraphQL that you’re trying to fetch data. It’s like a GET request in REST.
    • books: This is the name of the query. It corresponds to a field in the schema that returns a list of books.
    • { title, author }: This specifies the data you want for each book — only the title and author fields. This is what makes GraphQL powerful: you can ask for exactly the data you need, and nothing more.
  • Mutations are used to modify data. You can use mutations to create, update, or delete data.Here’s an example of a mutation to add a new book:graphqlCopyEditmutation { addBook(title: "The Great Gatsby", author: "F. Scott Fitzgerald") { id title author } } Explanation:
    • mutation: This indicates you’re trying to modify data (like POST or PUT in REST).
    • addBook: This is the name of the mutation. It corresponds to a field in your GraphQL schema that allows you to add a new book.
    • (title: "The Great Gatsby", author: "F. Scott Fitzgerald"): These are the arguments being passed to the mutation — in this case, the title and author of the new book.
    • { id, title, author }: These are the fields that you want the server to return after the mutation has been executed. Typically, after adding a new book, you’d want to see the id, title, and author fields.

Setting Up Your Node.js Project

Before we dive into the code, let’s set up a simple Node.js project where we will build the GraphQL API.

Environment Setup

Install Node.js and npm (Node Package Manager) if they’re not already installed. You can check by running:

Bash
node -v
npm -v

Initialize a Project:

Create a new directory for your project and initialize a new Node.js project with the following commands:

Bash
mkdir graphql-api && cd graphql-api
npm init -y

Install Dependencies

Now, install the necessary libraries for this project: express, express-graphql, and graphql. Run:

Bash
npm install express express-graphql graphql

These libraries help us set up the server, handle GraphQL requests, and build the GraphQL schema.

Folder Structure

Organizing your project structure makes it easier to scale as your application grows. Here’s how to structure your project:

Lua
graphql-api/
  |-- index.js
  |-- schema/
      |-- bookSchema.js

Middleware in GraphQL API

In any web application, middleware is used to process requests before they reach the actual route handlers. For GraphQL, middleware can handle tasks like logging requests, checking authentication, and handling errors.

Adding Middleware in Express

For example, if you want to log incoming requests, you can add this middleware in your index.js file:

JavaScript
app.use((req, res, next) => {
  console.log(`Request received: ${req.method} ${req.url}`);
  next(); // Pass the request to the next middleware
});

Explanation:

  • app.use(): This tells Express to use this middleware for all incoming requests.
  • (req, res, next) => {}: This is a simple middleware function where:
    • req represents the incoming request.
    • res represents the response we send back.
    • next() is used to pass control to the next middleware or route handler.

Defining Your Schema

In GraphQL, the schema defines the structure of your data, including the types, queries, and mutations available in your API.

Create a bookSchema.js file inside the schema folder. Here’s an example schema:

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

const schema = buildSchema(`
  type Book {
    id: ID!
    title: String!
    author: String!
  }

  type Query {
    books: [Book]
  }

  type Mutation {
    addBook(title: String!, author: String!): Book
  }
`);

module.exports = schema;

Explanation:

  • type Book: Defines the shape of a book object. It has three fields: id, title, and author.
    • ID! means the id field is required and will be a unique identifier.
    • String! means the title and author fields are required and will be strings.
  • type Query: Defines the available queries. In this case, we have a books query that returns an array of Book objects.
  • type Mutation: Defines the available mutations. In this case, the addBook mutation allows you to add a new book, requiring the title and author as arguments.

Creating Resolvers

Resolvers connect the schema to actual data. They provide the logic for how to fetch or modify data based on the schema’s fields.

Here’s an example of resolvers for fetching and adding books:

JavaScript
const resolvers = {
  books: () => [
    { id: 1, title: "1984", author: "George Orwell" },
    { id: 2, title: "Brave New World", author: "Aldous Huxley" }
  ],
  addBook: ({ title, author }) => {
    const book = { id: Date.now(), title, author };
    return book;
  }
};

Explanation:

  • books: This resolver simply returns an array of book objects. In a real application, you would fetch this data from a database.
  • addBook: This resolver accepts the title and author arguments and creates a new book object with a unique id (generated using Date.now()).

Integrating Middleware and Express

Now let’s connect the GraphQL schema and resolvers to Express. We’ll also set up a route to handle GraphQL queries.

Here’s how you do it in index.js:

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

const app = express();

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

app.listen(4000, () => console.log('Server running at http://localhost:4000/graphql'));

Explanation:

  • graphqlHTTP(): This function connects the GraphQL schema and resolvers to Express. It also enables the GraphiQL UI, which is a helpful tool for testing your GraphQL API in the browser.
  • app.listen(4000): This starts the server and listens for requests on port 4000. You can now access your GraphQL API at http://localhost:4000/graphql.

Testing the GraphQL API

Now that everything is set up, you can open your browser and go to http://localhost:4000/graphql to test your GraphQL API using GraphiQL.

For example, to fetch all books, run this query:

GraphQL
query {
  books {
    title
    author
  }
}

Conclusion

With the basics of GraphQL queries and mutations in place, you’re ready to start building powerful APIs. You’ve learned how to set up a Node.js project, define a GraphQL schema, create resolvers, and test your API.

What’s next? Explore advanced topics like connecting to databases or implementing real-time features with GraphQL subscriptions. Share your thoughts or questions in the comments below!

You Might Also Like