GraphQL

Build GraphQL CRUD API in Node & Express Server from Scratch – Part 1

January 29, 2018

author:

Build GraphQL CRUD API in Node & Express Server from Scratch – Part 1

Many people understand basics and advantages of GraphQL but fail to implement it in their project. This tutorial will hopefully be fruitful for such souls searching the web for a working example of GraphQL CRUD operations.

To set the expectations straight, we will create a book application with book name and author fields.

# Build GraphQL API in Node Server

We will start with creating a Node.js server with Express. And then dive into GraphQL implications like Types, Queries, Mutations and Schema. To test the application, we won’t really need to build a front-end or third party tool like PostMan. We will utilize GraphQL’s inbuilt tool GraphiQL for that. Anyway, that’s for a quite later stage. For now, let us get started with building a Node.js Express Server and GraphQL.

# Node Setup

First things first. Make sure you have the latest version of Node.js installed on your system.

node -v

Next, setup a new project directory and run following command to create a package.json file. (Note you can keep the default settings by pressing ENTER)

npm init

Since we will be building express server, go fetch express library:

npm install express --save

(--save flag is for future installs of your project directory)

# Express Server Setup

It’s now time to kick up the server. To do so, create a new file server.js in the root directory of the project:

# server.js

const express = require('express');

const PORT = process.env.PORT || 8080;
const app = express();

app.listen(PORT);
console.log('GraphQL API Server up and running at localhost:' + PORT);

Most of the code here is self-explanatory. All we are doing is import express library in our file, allocate a distinct port and create an express server to listen on that port. We can test the server by:

node server.js
GraphQL Node Server Running

# GraphQL Folder Structure

To eliminate the confusions at a later stage, let us discuss the folder structure for our project at staging level itself:

-data
    --books.js //store dummy JSON data
-src
    --graphql
        ---mutations.js //store GraphQL mutation
        ---queries.js   //store GraphQL query
        ---schema.js    //store GraphQL schema
        ---types.js     //store basic GraphQL  types for app
-server.js //express server setup
-package.json //store information about application and libraries
-node_modules //store installed packages

# GraphQL Setup

To integrate GraphQL in our node server, we must first install its package express-graphql. It will set up a middleware for GraphQL configurations.

npm install graphql express-graphql --save

Let us also import them into our server file:

# server.js
const graphqlHTTP = require('express-graphql');

# GraphQL and Node Integration

# server.js

const schema = require('./src/graphql/schema.js');

To integrate GraphQL, add the following lines in your servers.js. Though our schema isn’t ready now, we will set it up anyway so that we can keep testing the application as and when we want.

# server.js
...
const app = express();
app.use('/', graphqlHTTP({
    schema: schema,
    graphiql: true
}));

# Data Setup for GraphQL API

Since we are focusing on GraphQL API in this segment, we don’t really need an actual database. We can store data in a file for testing purpose. You can add following data:

# data/books.js

const Books = [
    { 
        id: "0d692339-6dc7-4cd0-8ad5-2af65d5cb6a7", 
        name: "The Fault in Our Stars", author: "John Green" }
        ,
    { 
        id: "1cc87605-a837-4801-ac99-f1c4b609fc10", 
        name: "Namesake", author: "Jhumpa Lahiri" 
    },
    { 
        id: "e7a2dfa2-8532-40e8-9211-71f952736d42", 
        name: "To Kill a Mockingbird", author: "Harper Lee" 
    }
];

module.exports = Books;

# GraphQL Read Data

# Type Setup

As discussed earlier, we are building a book application, and thus it makes sense to have a basic BookType in our GraphQL Schema which describes the overall fields of the book:

# src/graphql/types.js

const {
    GraphQLString,
    GraphQLNonNull,
    GraphQLObjectType,
    GraphQLInputObjectType
} = require('graphql');

const BookType = new GraphQLObjectType({
    name: 'BookType',
    description: 'Book list',
    fields: {
        id: { type: GraphQLString },
        name: { type: GraphQLString },
        author: { type: GraphQLString }
    }
});

module.exports = { BookType }

Here, we are specifying GraphQLObjectType to store our book list. We have defined the relevant fields id, name and author as GraphQLString types. Both this types are a part of the graphql library.

# GraphQL Query

Let us setup a base query endpoint that can be used for throughout our application to query and retrieve all the books any time:

# src/graphql/queries.js

const { GraphQLList, GraphQLObjectType } = require('graphql');

const { BookType } = require('./types.js');
const Books = require('../../data/books.js');

const BookQueryType = new GraphQLObjectType({
    name: 'BookQueryType',
    description: 'Query Schema for BookType',
    fields: {
        books: {
            type: new GraphQLList(BookType),
            resolve: () => Books
        }
    }
});

module.exports = BookQueryType;

We are defining a new GraphQLObjectType for our query with required properties name and fields and an optional description property for readability and API documentation.

# GraphQL Schema

Schema integrates everything (Query, Mutation and Subscriptions) in GraphQL. Let us wire the BookQueryType we created previously:

# src/graphql/schema.js

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

const BookQueryType = require('./queries.js');

const BooksSchema = new GraphQLSchema({
    query: BookQueryType
});

module.exports = BooksSchema;

# GraphQL Mutations

To create, update and delete data, GraphQL utilizes a feature called mutations. We can run them with the keyword mutation. But before doing that, let us define some mutations. Following our application and folder structure, we will first add a relevant type for each CRUD operation and build a mutation using that type.

# Insert Operation in GraphQL

First of all, since we are utilizing the file structure, we need to install some dependencies for our APIs:

npm install uuid lodash --save

# GraphQL Type to Create Object

For create operation in our GraphQL API, let’s define BookCreateType with relevant properties. Note that since we have already defined the basic schema for book data, we don’t really need to repeat ourselves there. We can use BookType as a type here:

# src/graphql/types.js

const BookType = new GraphQLObjectType({
    ...
});

const BookCreateType = new GraphQLInputObjectType({
    name: 'BookCreateType',
    description: 'Add a book to the list',
    type: BookType,
    fields: {
        name: { type: new GraphQLNonNull(GraphQLString) },
        author: { type: new GraphQLNonNull(GraphQLString) }
    }
});


module.exports = {
    BookType,
    BookCreateType
}

GraphQLInputObjectType helps us define input type for an argument in our mutations. It determines the required entities for performing mutation operation. GraphQLNonNull depicts that the corresponding field is a required field. Also, fields attribute holds only name and author as we will utilize uuid library for generating ids.

# Create Mutation

To perform insert operation in GraphQL, we utilize mutations. Create src/graphql/mutations.js file if you haven’t created already and put in the import statements:

# src/graphql/mutations.js

const uuidv4 = require('uuid/v4');
const { GraphQLNonNull, GraphQLObjectType } = require('graphql');

const {
    BookType,
    BookCreateType
} = require('./types.js');

const Books = require('../../data/books.js');

We are importing uuid library here which we will use in a moment. We are also importing BookType and BookCreateType which we will use in our mutation types. Next, we import Books.json to fetch the recorded data.

Let us now create root mutation type and add createBook mutation:

# src/graphql/mutations.js

//...import statements...
const BookMutationType = new GraphQLObjectType({
    name: 'BookMutationType',
    description: 'Mutations for BookType',
    fields: {
        createBook: {
            type: BookType,
            args: {
                input: { type: new GraphQLNonNull(BookCreateType) }
            },
            resolve: (source, { input }) => {
                let book = [];
                book.id = uuidv4();
                book.name = input.name;
                book.author = input.author;
                Books.push(book);
                return book;
            }
        }
    }
});

module.exports = BookMutationType;

createBook has type attribute which accepts BookType schema, args accepts the user input and resolve has our actual logic. We are generating a new data from user inputs and uuid using es6 syntax.

# GraphQL Schema

Let us now wire our BookMutationType in the schema:

# src/graphql/schema.js
...
const BookMutationType = require('./mutations.js');

const BooksSchema = new GraphQLSchema({
    query: BookQueryType,
    mutation: BookMutationType
});

...

# Testing GraphQL API

We are still left with an update and delete operation but out of the habit of unit testing, let us just try and test the graphql application:

node server.js
http://localhost:8080

Test following operations:

query getAllBooks {
  books {
    id
    name
    author
  }
}
GraphQL CRUD read operation

Remember that a mutation payload must return at least one field even if no data is really required. Test the following mutation:

mutation createNewBook {
  createBook(input: {
    name: "The Underground Railroad",
    author: "Colson Whitehead"
  }) {
    id
    name
    author
  }
}
GraphQL CRUD Create Mutation

Conclusion:

We started building GraphQL API using Node.js server and have completed various setups. We also worked on read and write (insert) operation. In the coming segment, we will complete the CRUD API with the update and delete operations.

Questions & Comments:

What a session! It is fun building GraphQL Applications, isn’t it? If you have got any questions/suggestions on working with GraphQL API server, add them in the comment section below.

Leave a comment

Your email address will not be published. Required fields are marked *