Building a Basic GraphQL API with Apollo Client in Node js

Marydera UgorjiMarydera Ugorji
7 min read

Creating efficient and scalable APIs is paramount in modern web development. GraphQL provides an alternative to traditional RESTful APIs, delivering increased flexibility and performance improvements. This tutorial focuses on creating a GraphQL API with Apollo Client in Node.js. Apollo Server, a popular GraphQL server implementation, simplifies the task of constructing and deploying GraphQL APIs. Through a systematic approach, we'll walk through setting up a basic GraphQL API using Apollo Server, which involves defining schemas, implementing resolvers, and testing our API endpoints.

Overview of Apollo Server

Apollo Server is a specialized GraphQL server designed to simplify the process of creating and deploying GraphQL APIs. Its adaptability facilitates easy integration with different data sources and existing infrastructure. Its main focus is on improving the efficiency and performance of API development.

A key component of Apollo Server is its robust schema management system, which allows developers to define clear and consistent API structures using the GraphQL schema language. Alongside schema management, Apollo Server offers efficient data fetching mechanisms, including built-in support for data loading, caching, and error handling. These features enable developers to optimize API performance by efficiently retrieving and processing data from various sources.

Additionally, Apollo Server provides essential tools for monitoring and debugging GraphQL APIs, ensuring that developers have the necessary insights to effectively maintain and troubleshoot their applications.

Setting Up the Development Environment

To begin setting up the environment for our article, we need to ensure that several prerequisites are already installed on your system. These include Node.js, Node Package Manager (NPM), and Visual Studio Code (VS Code).

Once you've confirmed that these prerequisites are in place, the next step is to create a new directory and navigate into it. This can be achieved by executing the following commands in your command line interface:

// Create a new folder
mkdir <folder_name>

// Move into the new folder
cd <folder_name>

With the directory created and navigated into, you can proceed to open the folder in VS Code by running:

code .

Now that we have our environment set up, let's initialize a Node.js project. In your command line, execute the following command:

npm init

This command will prompt you to provide some information about your project, such as the package name and version. You can accept the default values or customize them according to your preferences. Once completed, a package.json file will be generated in your project folder.

To install the necessary dependencies for our project, run the following command:

npm install @apollo/server colors graphql nodemon

These dependencies include apollo/server, colors, graphql, and nodemon.

Next, let's configure the start script in our package.json file. Within the "scripts" section, add the following line:

"scripts": {
    "start": "nodemon ./index.mjs"
},

This script defines how to start your application using nodemon, which will automatically restart the server when changes are detected.

Now that our environment is set up and dependencies are installed, we can begin building our GraphQL API. A typical GraphQL API consists of three main parts: the server, the schema, and the resolvers. To organize our project, let's create three files named index.mjs, schema.mjs, and resolvers.mjs.

Creating Apollo Server

To kickstart the API creation process, we first focus on setting up the server. This involves importing necessary modules and defining configurations in the index.mjs file. Specifically, we import the colors, ApolloServer, typeDefs, and resolvers modules:

import 'colors';
import { ApolloServer } from 'apollo-server';
import { typeDefs } from './schema.mjs';
import { resolvers } from './resolvers.mjs';

Next, we establish a constant variable named API_PORT and assign it the value 4000, designating it as the port number for the GraphQL server:

const API_PORT = 4000;

Proceeding with the server setup, we instantiate a new ApolloServer, providing it with the defined type definitions (typeDefs) and resolvers. These components respectively outline the structure of available data in the GraphQL API and specify how to retrieve or manipulate that data:

const server = new ApolloServer({
    typeDefs,
    resolvers
});

With the server configured, we initiate its operation. Using the listen method on the server instance, we specify the port for incoming requests. Here, we use the API_PORT variable, defaulting to port 4000 if it's undefined.

Upon successful server startup, a message is logged to the console, indicating readiness to accept requests along with the server's URL. Additionally, a hint is provided regarding where to query the API using Apollo Studio. In case of any errors during startup, they are caught and logged accordingly.

server.listen({ port: API_PORT || 4000 }).then(({ url }) => {
    console.log(`Server is ready at: `.green + `${url}`.yellow);
    console.log('Query at: '.magenta + 'https://studio.apollographql.com/dev'.yellow);
}).catch((error) => {
    console.log(error);
});

Defining GraphQL Schema

To create a GraphQL schema, start by understanding the core concepts which are types, queries, and mutations.

  • Types: Types are fundamental in GraphQL as they determine the structure of data accessible through your API. Scalar types represent basic data types such as Int, String, Boolean, etc., while Object types define more complex data structures.

  • Queries: Queries specify how clients can retrieve data from the GraphQL server. Each query is linked to a specific type and outlines the fields that clients can request.

  • Mutations: Mutations govern how clients can alter or create data on the server. Like queries, mutations are tied to specific types and define the fields that clients can utilize for operations.

Defining types, queries, and mutations

To begin, import the gql function from the apollo-server package:

import { gql } from "apollo-server"

Next, export an object named typeDefs, which contains the GraphQL schema utilizing the gql function. This schema encompasses the types, queries, and mutations available in your API.

Define a Query type as the entry point for fetching data from your API. Within the Query object, include a query field named checkApiStatus, returning an object of type ApiStatus.

Then, define a Mutation type for operations modifying data on the server. Inside the Mutation object, add a mutation field named testMutations, accepting an input string and returning an object of type Test.

Custom types representing your data's structure can also be defined. In this instance, create two custom types: ApiStatus and Test. Each type features one field, status, of type String.

export const typeDefs = gql`
    type Query {
        checkApiStatus: ApiStatus
    }
    type Mutation {
        testMutations(input: String): Test
    }
    type ApiStatus {
        status: String
    }
    type Test {
        status: String
    }
`

Creating Resolvers

GraphQL resolvers are pivotal functions tasked with retrieving data for each field in a GraphQL schema. Acting as intermediaries, they facilitate communication between incoming GraphQL queries and the underlying data sources, which can span databases, APIs, or other systems.

To define a resolver, begin by exporting an object named resolvers. Within this object, include resolver functions tailored to each GraphQL type outlined in your schema.

Under the resolvers object, establish a property named Query, housing resolver functions for each query stipulated in your schema. Each query resolver function corresponds to a particular field within the schema's Query type.

For instance, the schema features a query field labeled checkApiStatus, a resolver function for this field should be articulated within the Query object. This resolver function is straightforward, merely returning an object with the data, such as a status field affirming the API's operational status.

Similarly, within the resolvers object, incorporate a property named Mutation, housing resolver functions for each mutation delineated in the schema. These mutation resolver functions align with specific fields within the schema's Mutation type.

For example, the schema includes a mutation field named testMutations, and a corresponding resolver function should be defined within the Mutation object. Typically an asynchronous function, this resolver returns an object signaling the status of mutations.

export const resolvers = {
    Query: {
        checkApiStatus: () => {
            return { status: 'The API is currently working' }
        }
    },
    Mutation: {
        testMutations: async () => {
            return {
                status: 'Mutations are working.'
            }
        }
    }
}

Upon configuring the resolvers, initiate the application by executing npm start in the command line. Below is a snapshot of what our console outputs while our application runs.

Furthermore, validation and testing can be conducted through platforms like https://studio.apollographql.com/dev. By clicking the Example Query button we can see the response from our API.

To test mutations, create a new operation and append the following script:

mutation {
  testMutations(input: "") {
    status
  }
}

On clicking the run button, we get the response “Mutation is working” outputted.

Conclusion

Mastering GraphQL API development with Apollo Client unlocks a multitude of opportunities in modern web development. Apollo Server, with its streamlined schema management, efficient data fetching mechanisms, and robust tooling, simplifies the creation and deployment of GraphQL APIs. By acquiring the insights provided in this tutorial, you gain the skills necessary to address various challenges in GraphQL API development, ranging from designing intricate schemas to optimizing performance.

0
Subscribe to my newsletter

Read articles from Marydera Ugorji directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Marydera Ugorji
Marydera Ugorji