GraphQL with Apollo and Next.js

GraphQL with Apollo and Next.js

Learn how to use Apollo server and client along with Next.js front-end to access MongoDB using GraphQL. Free open-source tutorial on basic GraphQL application with Apollo server and client rendered via Next.js

Learn how to use Apollo server and client along with Next.js front-end to access MongoDB using GraphQL.

Angular 9 Tutorial: Learn to Build a CRUD Angular App Quickly

What's new in Bootstrap 5 and when Bootstrap 5 release date?

What’s new in HTML6

How to Build Progressive Web Apps (PWA) using Angular 9

What is new features in Javascript ES2020 ECMAScript 2020

Building a GraphQL Client in JS with React and MongoDB

Building a GraphQL Client in JS with React and MongoDB

Learn how to build a GraphQL Client in JS with React and MongoDB. GraphQL is the future of API. Together we will start with the basics and the philosophy behind the brand new GraphQL feature on MongoDB Stitch. We will leave with a working GraphQL client while we explore real world GraphQL patterns.

GraphQL is the future of API. Together we will start with the basics and the philosophy behind the brand new GraphQL feature on MongoDB Stitch. By the end of the stream, we will leave with a working GraphQL client while we explore real world GraphQL patterns.

Explore GraphQL with Apollo & React: Build a Superhero Database

Explore GraphQL with Apollo & React: Build a Superhero Database

In this article, We share some light on what GraphQL is and give you an opportunity for some hands-on experience with Apollo and React.

In this article, We share some light on what GraphQL is and give you an opportunity for some hands-on experience with Apollo and React.

Curious about all the buzz surrounding GraphQL, but not quite sure why you should be excited? You’re in the right place! We’ll shed some light on what GraphQL is and give you an opportunity for some hands-on experience.

Let’s start by clearing the air and answering the $20,000 question: what is GraphQL? No, it’s not an obscure function on your TI-89. It’s a query language at heart — or query specification more accurately — that can be used to fetch data from just about any data source.

Better yet, it allows you to fetch the exact data you need — no more, no less — in a single network request. While that may not sound like the sexiest tech to come out of the Facebook factory of innovation, you may just find yourself pleasantly surprised at how useful it can be.

All that’s needed is an Apollo server to act as our endpoint and a React app using the Apollo client to leverage any data within. We’ll tackle the server first.

Getting Started with Apollo Server

To get our Apollo server started, create a folder called apollo-server in your favorite working directory. Next, enter that directory and run the following npm command — you do have npm and Node installed, right? — to get the Apollo framework in place:

npm install apollo-server apollo-server-express graphql

Now that you’ve got the various bits and pieces of the Apollo server in place, it’s time to actually tell our server what to serve. Go ahead and create an empty index.js file in the apollo-server directory and add the following to it:

const { ApolloServer, gql } = require('apollo-server');

This line simply pulls in the required objects for starting an Apollo server and parsing our query strings into query documents for GraphQL.

Our First GraphQL Schema

Next up, let’s add our first schema:

// This will be our GraphQL schema
const typeDefs = gql`
  type User {
    id: ID!
    name: String
    superpowers: [Superpower]!
  }

  type Superpower {
    id: ID!
    text: String
  }

  type Query {
    users: [User]
    user(id: ID!): User
  }
`;

Here we add our type definitions. The first is of type User which we define as an object having an id, name, and superpowers field. The second is a simple id and text to describe each superpower. Finally, the third defines two acceptable queries — users and user — that, respectively, return all users or a single user that matches the provided id argument.

Pretty easy, right?

Adding a Dash of Data

Next, let’s add some mock data to bring our schema to life:

// This will be our mock data to query
const users = [{
  id: '1',
  name: 'Peter Parker',
  superpowers: [{
    id: '1',
    text: 'Web slinging'
  },{
    id: '2',
    text: 'Spidey sense'
  }]
},{
  id: '2',
  name: 'Tony Stark',
  superpowers: [{
    id: '3',
    text: 'Industrial design'
  },{
    id: '4',
    text: 'Robotic fashion'
  }]
}];

All we’re doing here is adding two users to our mock data. It’s worth pointing out that GraphQL isn’t relegated to only querying JavaScript arrays. This could be any database or other data construct. We’re just keeping things simple here to focus on the task at hand.

Don’t Forget Resolvers

Next up, we need to tell GraphQL how to interpret the queries we defined above. This is done with resolvers:

// This will be a map of functions to return the data described by our schema
const resolvers = {
  Query: {
    users: () => {
      return users
    },
    user: (root, { id }) => {
      return users.find(user => user.id === id);
    },
  },
};

You’ll notice the first query users requires no arguments and returns the entire users list (at least in theory, more on that later). The second query user accepts the ID of the user to be fetched and returns said user.

Putting It All Together

To finish off our Apollo server, we just need to instantiate a new instance and start listening for connections:

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

server.listen().then(({ url }) => {
  console.log(`Apollo server started at ${url}`)
});

Here we send the ApolloServer constructor our schema and resolvers created above. All that’s needed then is to actually start the server, but first, here’s what your index.js should look like:

const { ApolloServer, gql } = require('apollo-server');

// This will be our GraphQL schema
const typeDefs = gql`
  type User {
    id: ID!
    name: String
    superpowers: [Superpower]!
  }

  type Superpower {
    id: ID!
    text: String
  }

  type Query {
    users: [User]
    user(id: ID!): User
  }
`;

// This will be our mock data to query
const users = [{
  id: '1',
  name: 'Peter Parker',
  superpowers: [{
    id: '1',
    text: 'Web slinging'
  },{
    id: '2',
    text: 'Spidey sense'
  }]
},{
  id: '2',
  name: 'Tony Stark',
  superpowers: [{
    id: '3',
    text: 'Industrial design'
  },{
    id: '4',
    text: 'Robotic fashion'
  }]
}];

// This will be a map of functions to return the data described by our schema
const resolvers = {
  Query: {
    users: () => {
      return users
    },
    user: (root, { id }) => {
      return users.find(user => user.id === id);
    },
  },
};

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

server.listen().then(({ url }) => {
  console.log(`Apollo server started at ${url}`)
});

Go ahead and fire it up with node index.js and visit http://localhost:4000/ to see the fruit of your labor!

You should be greeted with a GraphQL playground that lets you try out interactive queries against the schema you’ve created.

Going Hands-on

Let’s test it out by entering this query in the left-hand pane:

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

Here we use the user query we just set up, and pass it the id of 1. We’re also telling GraphQL that we only want to return the name of said user. The result in the left hand pane — after clicking the play-like button — should look like this:

{
  "data": {
    "user": {
      "name": "Peter Parker"
    }
  }
}

Let’s say you want to take a peek at his superpowers too. All you have to do is request that field:

query {
  user(id: 1) {
    name,
    superpowers {
      text
    }
  }
}

We added the superpowers field and, since we only care about the text and not the superpower ID, we specify as much. The result should now display each superpower for our first user:

{
  "data": {
    "user": {
      "name": "Peter Parker",
      "superpowers": [
        {
          "text": "Web slinging"
        },
        {
          "text": "Spidey sense"
        }
      ]
    }
  }
}

Say we want to grab all users and their superpowers, we can rely on the users query we defined:

query {
  users {
    id,
    name,
    superpowers {
      text
    }
  }
}

And the result:

{
  "data": {
    "users": [
      {
        "id": "1",
        "name": "Peter Parker",
        "superpowers": [
          {
            "text": "Web slinging"
          },
          {
            "text": "Spidey sense"
          }
        ]
      },
      {
        "id": "2",
        "name": "Tony Stark",
        "superpowers": [
          {
            "text": "Industrial design"
          },
          {
            "text": "Robotic fashion"
          }
        ]
      }
    ]
  }
}

Only care about superpowers? We can do that too:

query {
  users {
    superpowers {
      text
    }
  }
}

And you get:

{
  "data": {
    "users": [
      {
        "superpowers": [
          {
            "text": "Web slinging"
          },
          {
            "text": "Spidey sense"
          }
        ]
      },
      {
        "superpowers": [
          {
            "text": "Industrial design"
          },
          {
            "text": "Robotic fashion"
          }
        ]
      }
    ]
  }
}

At this point you should be able to appreciate the supreme flexibility and allure of GraphQL. With a single query and connection we can retrieve any slice of the data we desire. All that’s necessary is a well designed schema and the resolvers to support it.

Even better, back-end developers and front-end developers can do their thing almost independently. With the schema acting as a middle man, both groups can effectively avoid stepping on each other’s toes. And really, that’s GraphQL in a nutshell. Before we wrap this tutorial up however, let’s take a look at how to integrate these queries with an actual React app.

Introducing React to the Mix

Go back to your root working directory and run the following commands to set up a bootstrapped React app with the requisite GraphQL and Apollo libraries:

npm install -g create-react-app
create-react-app my-graphql
cd my-graphql
npm install apollo-boost react-apollo graphql

Next, replace the contents of src/index.js with the following:

index.js:

import React from 'react'
import ReactDOM from 'react-dom'
import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloProvider } from 'react-apollo'

import App from './App'

const client = new ApolloClient({
    link: new HttpLink({ uri: 'http://localhost:4000/graphql' }),
    cache: new InMemoryCache()
})

ReactDOM.render(
    <ApolloProvider client={client}>
    <App />
    </ApolloProvider>,
    document.getElementById('root')
)

All we need here are the usual imports for a React app along with the Apollo client to interface with our new Apollo server. To create the Apollo client we just need a link to the server http://localhost:4000/graphql and a way to cache our goods. With that, we simply render the app.

Next, we need to set up the app to query and display the data presented by our Apollo server. Go ahead and replace the default src/App.js with this:

App.js:

import React from 'react'
import { Query } from 'react-apollo'
import { gql } from 'apollo-boost'

const TEST_QUERY = gql`
  {
    user(id: 1) {
      id,
      name,
      superpowers {
        text
      }

  }}
`;

const App = () => (
  <Query query={TEST_QUERY}>
  {({ data: { user }, loading }) => {
      if (loading || !user) {
        return <div>Loading ...</div>;
      }
      return (
    <p>
        {user.name} ({user.id}) has the following superpowers:
        <ul>
        {user.superpowers.map(superpower => (
            <li>
                {superpower.text}
            </li>
        ))}
        </ul>
    </p>
      );
    }}
  </Query>
);

export default App

You should see some familiar patterns here. We first use gql to create a GraphQL query document that requests the user with ID 1 — more specifically, their ID, name and superpowers text. Then we pass the document to our server with the Query tag. It’s here that we can format the results in a pretty React app.

Go ahead and start the server with npm start and check out the beautiful results at http://localhost:3000/.

And with that, our tutorial is complete. You’ve created an Apollo server and fed it some simple data structures. You discovered how to write schemas and resolvers to define interactions with the data. You then practiced querying specific pieces of that data. Finally, you tied it all together with a React app that retrieves data from the server and presents it in a nicely formatted way.

While this should be enough to get you started with integrating GraphQL in your future projects, there’s lots still to learn. Mutations for adding and changing data is a great next step.

Node, Express, React.js, Graphql and MongoDB CRUD Web Application

Node, Express, React.js, Graphql and MongoDB CRUD Web Application

In this tutorial, we just change the client side by using React.js and the backend still the same. Don’t worry, we will show the full tutorial from the server and the client side. We are using React Apollo library for fetch GraphQL data.

A comprehensive step by step tutorial on building CRUD (create, read, update, delete) web application using React.js and GraphQL using React-Apollo. Previously, we have to build CRUD web application using Node, Express, Angular 7 and GraphQL.

Table of Contents:
  • Create Express.js App
  • Install and Configure Mongoose.js Modules for Accessing MongoDB
  • Create Mongoose.js Model for the Book Document
  • Install GraphQL Modules and Dependencies
  • Create GraphQL Schemas for the Book
  • Add Mutation for CRUD Operation to the Schema
  • Test GraphQL using GraphiQL
  • Create React.js Application
  • Install and Configure Required Modules and Dependencies
  • Create React.js Router DOM]
  • Create a Component to Display List of Books
  • Create a Component to Show and Delete Books
  • Create a Component to Add a New Book
  • Create a Component to Edit a Book
  • Run and Test GraphQL CRUD from the React.js Application

The following tools, frameworks, and modules are required for this tutorial:

  • Node.js (choose recommended version)
  • React.js
  • Express.js
  • GraphQL
  • Express-GraphQL
  • React Apollo
  • Terminal (Mac/Linux) or Node Command Line (Windows)
  • IDE or Text Editor (We are using Visual Studio Code)

We assume that you have already Installed Node.js. Make sure Node.js command line is working (on Windows) or runnable in Linux/OS X terminal.

1. Create Express.js App

If Express.js Generator hasn’t installed, type this command from the terminal or Node.js command prompt.

sudo npm install express-generator -g

The sudo keyword is using in OSX or Linux Terminal otherwise you can use that command without sudo. Before we create an Express.js app, we have to create a root project folder inside your projects folder. From the terminal or Node.js command prompt, type this command at your projects folder.

mkdir node-react-graphql

Go to the newly created directory.

cd ./node-react-graphql

From there, type this command to generate Express.js application.

express server

Go to the newly created Express.js app folder.

cd ./server

Type this command to install all required NPM modules that describe in package.json dependencies.

npm install

To check the Express.js app running smoothly, type this command.

nodemon

or

npm start

If you see this information in the terminal or command prompt that means your Express.js app is ready to use.

[nodemon] 1.18.6
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `node ./bin/www`

2. Install and Configure Mongoose.js Modules for Accessing MongoDB

To install Mongoose.js and it’s required dependencies, type this command.

npm install mongoose bluebird --save

Next, open and edit app.js then declare the Mongoose module.

var mongoose = require('mongoose');

Create a connection to the MongoDB server using this lines of codes.

mongoose.connect('mongodb://localhost/node-graphql', { promiseLibrary: require('bluebird'), useNewUrlParser: true })
  .then(() =>  console.log('connection successful'))
  .catch((err) => console.error(err));

Now, if you re-run again Express.js server after running MongoDB server or daemon, you will see this information in the console.

[nodemon] 1.18.6
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `node ./bin/www`
connection successful

That’s mean, the connection to the MongoDB is successful.

3. Create Mongoose.js Model for the Book Document

Before creating a Mongoose.js model that represents Book Document, we have to create a folder at the server folder for hold Models. After that, we can create a Mongoose.js model file.

mkdir models
touch models/Book.js

Open and edit server/models/Book.js then add these lines of codes.

var mongoose = require('mongoose');

var BookSchema = new mongoose.Schema({
  id: String,
  isbn: String,
  title: String,
  author: String,
  description: String,
  published_year: { type: Number, min: 1945, max: 2019 },
  publisher: String,
  updated_date: { type: Date, default: Date.now },
});

module.exports = mongoose.model('Book', BookSchema);

4. Install GraphQL Modules and Dependencies

Now, the GraphQL time. Type this command to install GraphQL modules and it’s dependencies.

npm install express express-graphql graphql graphql-date cors --save

Next, open and edit server/app.js then declare all of those modules and dependencies.

var graphqlHTTP = require('express-graphql');
var schema = require('./graphql/bookSchemas');
var cors = require("cors");

The schema is not created yet, we will create it in the next steps. Next, add these lines of codes for configuring GraphQL that can use over HTTP.

app.use('*', cors());
app.use('/graphql', cors(), graphqlHTTP({
  schema: schema,
  rootValue: global,
  graphiql: true,
}));

That’s configuration are enabled CORS and the GraphiQL. GraphiQL is the user interface for testing GraphQL query.

5. Create GraphQL Schemas for the Book

Create a folder at the server folder for hold GraphQL Schema files then create a Javascript file for the schema.

mkdir graphql
touch graphql/bookSchemas.js

Next, open and edit server/graphql/bookSchemas.js then declares all required modules and models.

var GraphQLSchema = require('graphql').GraphQLSchema;
var GraphQLObjectType = require('graphql').GraphQLObjectType;
var GraphQLList = require('graphql').GraphQLList;
var GraphQLObjectType = require('graphql').GraphQLObjectType;
var GraphQLNonNull = require('graphql').GraphQLNonNull;
var GraphQLID = require('graphql').GraphQLID;
var GraphQLString = require('graphql').GraphQLString;
var GraphQLInt = require('graphql').GraphQLInt;
var GraphQLDate = require('graphql-date');
var BookModel = require('../models/Book');

Create a GraphQL Object Type for Book models.

var bookType = new GraphQLObjectType({
  name: 'book',
  fields: function () {
    return {
      _id: {
        type: GraphQLString
      },
      isbn: {
        type: GraphQLString
      },
      title: {
        type: GraphQLString
      },
      author: {
        type: GraphQLString
      },
      description: {
        type: GraphQLString
      },
      published_year: {
        type: GraphQLInt
      },
      publisher: {
        type: GraphQLString
      },
      updated_date: {
        type: GraphQLDate
      }
    }
  }
});

Next, create a GraphQL query type that calls a list of book and single book by ID.

var queryType = new GraphQLObjectType({
  name: 'Query',
  fields: function () {
    return {
      books: {
        type: new GraphQLList(bookType),
        resolve: function () {
          const books = BookModel.find().exec()
          if (!books) {
            throw new Error('Error')
          }
          return books
        }
      },
      book: {
        type: bookType,
        args: {
          id: {
            name: '_id',
            type: GraphQLString
          }
        },
        resolve: function (root, params) {
          const bookDetails = BookModel.findById(params.id).exec()
          if (!bookDetails) {
            throw new Error('Error')
          }
          return bookDetails
        }
      }
    }
  }
});

Finally, exports this file as GraphQL schema by adding this line at the end of the file.

module.exports = new GraphQLSchema({query: queryType});

6. Add Mutation for CRUD Operation to the Schema

For completing CRUD (Create, Read, Update, Delete) operation of the GraphQL, we need to add a mutation that contains create, update and delete operations. Open and edit server/graphql/bookSchemas.js then add this mutation as GraphQL Object Type.

var mutation = new GraphQLObjectType({
  name: 'Mutation',
  fields: function () {
    return {
      addBook: {
        type: bookType,
        args: {
          isbn: {
            type: new GraphQLNonNull(GraphQLString)
          },
          title: {
            type: new GraphQLNonNull(GraphQLString)
          },
          author: {
            type: new GraphQLNonNull(GraphQLString)
          },
          description: {
            type: new GraphQLNonNull(GraphQLString)
          },
          published_year: {
            type: new GraphQLNonNull(GraphQLInt)
          },
          publisher: {
            type: new GraphQLNonNull(GraphQLString)
          }
        },
        resolve: function (root, params) {
          const bookModel = new BookModel(params);
          const newBook = bookModel.save();
          if (!newBook) {
            throw new Error('Error');
          }
          return newBook
        }
      },
      updateBook: {
        type: bookType,
        args: {
          id: {
            name: 'id',
            type: new GraphQLNonNull(GraphQLString)
          },
          isbn: {
            type: new GraphQLNonNull(GraphQLString)
          },
          title: {
            type: new GraphQLNonNull(GraphQLString)
          },
          author: {
            type: new GraphQLNonNull(GraphQLString)
          },
          description: {
            type: new GraphQLNonNull(GraphQLString)
          },
          published_year: {
            type: new GraphQLNonNull(GraphQLInt)
          },
          publisher: {
            type: new GraphQLNonNull(GraphQLString)
          }
        },
        resolve(root, params) {
          return BookModel.findByIdAndUpdate(params.id, { isbn: params.isbn, title: params.title, author: params.author, description: params.description, published_year: params.published_year, publisher: params.publisher, updated_date: new Date() }, function (err) {
            if (err) return next(err);
          });
        }
      },
      removeBook: {
        type: bookType,
        args: {
          id: {
            type: new GraphQLNonNull(GraphQLString)
          }
        },
        resolve(root, params) {
          const remBook = BookModel.findByIdAndRemove(params.id).exec();
          if (!remBook) {
            throw new Error('Error')
          }
          return remBook;
        }
      }
    }
  }
});

Finally, add this mutation to the GraphQL Schema exports like below.

module.exports = new GraphQLSchema({query: queryType, mutation: mutation});

7. Test GraphQL using GraphiQL

To test the queries and mutations of CRUD operations, re-run again the Express.js app then open the browser. Go to this address <a href="http://localhost:3000/graphql" target="_blank">http://localhost:3000/graphql</a> to open the GraphiQL User Interface.

To get the list of books, replace all of the text on the left pane with this GraphQL query then click the Play button.

To get a single book by ID, use this GraphQL query.

{
  book(id: "5c738dd4cb720f79497de85c") {
    _id
    isbn
    title
    author
    description
    published_year
    publisher
    updated_date
  }
}

To add a book, use this GraphQL mutation.

mutation {
  addBook(
    isbn: "12345678",
    title: "Whatever this Book Title",
    author: "Mr. Bean",
    description: "The short explanation of this Book",
    publisher: "Djamware Press",
    published_year: 2019
  ) {
    updated_date
  }
}

You will the response at the right pane like this.

{
  "data": {
    "addBook": {
      "updated_date": "2019-02-26T13:55:39.160Z"
    }
  }
}

To update a book, use this GraphQL mutation.

mutation {
  updateBook(
    id: "5c75455b146dbc2504b94012",
    isbn: "12345678221",
    title: "The Learning Curve of GraphQL",
    author: "Didin J.",
    description: "The short explanation of this Book",
    publisher: "Djamware Press",
    published_year: 2019
  ) {
    _id,
    updated_date
  }
}

You will see the response in the right pane like this.

{
  "data": {
    "updateBook": {
      "_id": "5c75455b146dbc2504b94012",
      "updated_date": "2019-02-26T13:58:35.811Z"
    }
  }
}

To delete a book by ID, use this GraphQL mutation.

mutation {
  removeBook(id: "5c75455b146dbc2504b94012") {
    _id
  }
}

You will see the response in the right pane like this.

{
  "data": {
    "removeBook": {
      "_id": "5c75455b146dbc2504b94012"
    }
  }
}

8. Install and Create React.js Application

Open the terminal or Node.js command line then go to your React.js projects folder. We will install React.js app creator for creating a React.js app easily. For that, type this command.

sudo npm install -g create-react-app

Now, create a React app by type this command after back to the root of the project folder.

cd ..
create-react-app client

This command will create a new React app with the name client and this process can take minutes because all dependencies and modules also installing automatically. Next, go to the newly created app folder.

cd ./client

Now, run the React app for the first time using this command.

npm start

It will automatically open the default browser the point to <a href="http://localhost:3000" target="_blank">http://localhost:3000</a>, so the landing page should be like this.

9. Install and Configure Required Modules and Dependencies

Now, we have to install and configure all of the required modules and dependencies. Type this command to install the modules.

npm install apollo-boost react-apollo graphql-tag graphql --save

Next, open and edit client/src/index.js then add these imports.

import ApolloClient from 'apollo-boost';
import { ApolloProvider } from 'react-apollo';

Instantiate ApolloClient module as a variable before the React.js class name.

const client = new ApolloClient();

Add the ApolloProvider to the root of React.js component.

ReactDOM.render(
    <ApolloProvider client={client}>
        <App />
    </ApolloProvider>, 
    document.getElementById('root')
);

10. Create React.js Router DOM

Before creating React Router DOM, first, we have to install the required NPM modules by typing these commands.

npm install --save react-router-dom
npm install --save-dev bootstrap

The React.js CRUD web application required pages to creating, show details and edit Book data. For that, type this commands to create those components.

mkdir src/components
touch src/components/Create.js
touch src/components/Show.js
touch src/components/Edit.js

Next, we will create routes for those components. Open and edit src/index.js then add these imports.

import { BrowserRouter as Router, Route } from 'react-router-dom';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import Edit from './components/Edit';
import Create from './components/Create';
import Show from './components/Show';

Add React Router to the ReactDOM render.

ReactDOM.render(
    <ApolloProvider client={client}>
        <App />
    </ApolloProvider>, 
    <Router>
        <div>
            <Route exact path='/' component={App} />
            <Route path='/edit/:id' component={Edit} />
            <Route path='/create' component={Create} />
            <Route path='/show/:id' component={Show} />
        </div>
    </Router>,
    document.getElementById('root')
);

As you see that Edit, Create and Show added as the separate component. Bootstrap also included in the import to make the views better.

11. Create a Component to Display List of Books

We need to add graphql-tag to use GraphQL query with React.js. Type this command to install it.

npm install graphql-tag --save

Next, open and edit client/App.js then replace all imports with these.

import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import './App.css';
import gql from 'graphql-tag';
import { Query } from 'react-apollo';

Declare a constant before the class name for the query.

const GET_BOOKS = gql`
  {
    books {
      _id
      title
      author
    }
  }
`;

Replace all render function contents with these.

render() {
    return (
      <Query pollInterval={500} query={GET_BOOKS}>
        {({ loading, error, data }) => {
          if (loading) return 'Loading...';
          if (error) return `Error! ${error.message}`;

          return (
            <div className="container">
              <div className="panel panel-default">
                <div className="panel-heading">
                  <h3 className="panel-title">
                    LIST OF BOOKS
                  </h3>
                  <h4><Link to="/create">Add Book</Link></h4>
                </div>
                <div className="panel-body">
                  <table className="table table-stripe">
                    <thead>
                      <tr>
                        <th>Title</th>
                        <th>Author</th>
                      </tr>
                    </thead>
                    <tbody>
                      {data.books.map((book, index) => (
                        <tr key={index}>
                          <td><Link to={`/show/${book._id}`}>{book.title}</Link></td>
                          <td>{book.title}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              </div>
            </div>
          );
        }}
      </Query>
    );
}

12. Create a Component to Show and Delete Books

As you see in previous steps, it’s a link to show the details of the Book. For that, open and edit client/components/Show.js then add these imports.

import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import '../App.css';
import gql from 'graphql-tag';
import { Query, Mutation } from 'react-apollo';

Add the constants variables of query and mutation before the class name.

const GET_BOOK = gql`
    query book($bookId: String) {
        book(id: $bookId) {
            _id
            isbn
            title
            author
            description
            published_year
            publisher
            updated_date
        }
    }
`;

const DELETE_BOOK = gql`
  mutation removeBook($id: String!) {
    removeBook(id:$id) {
      _id
    }
  }
`;

Add class with the name Show as below.

class Show extends Component {

  render() {
    return (
        <Query pollInterval={500} query={GET_BOOK} variables={{ bookId: this.props.match.params.id }}>
            {({ loading, error, data }) => {
                if (loading) return 'Loading...';
                if (error) return `Error! ${error.message}`;

                return (
                    <div className="container">
                        <div className="panel panel-default">
                            <div className="panel-heading">
                            <h4><Link to="/">Book List</Link></h4>
                                <h3 className="panel-title">
                                {data.book.title}
                                </h3>
                            </div>
                            <div className="panel-body">
                                <dl>
                                    <dt>ISBN:</dt>
                                    <dd>{data.book.isbn}</dd>
                                    <dt>Author:</dt>
                                    <dd>{data.book.author}</dd>
                                    <dt>Description:</dt>
                                    <dd>{data.book.description}</dd>
                                    <dt>Published Year:</dt>
                                    <dd>{data.book.published_year}</dd>
                                    <dt>Publisher:</dt>
                                    <dd>{data.book.publisher}</dd>
                                    <dt>Updated:</dt>
                                    <dd>{data.book.updated_date}</dd>
                                </dl>
                                <Mutation mutation={DELETE_BOOK} key={data.book._id} onCompleted={() => this.props.history.push('/')}>
                                    {(removeBook, { loading, error }) => (
                                        <div>
                                            <form
                                                onSubmit={e => {
                                                    e.preventDefault();
                                                    removeBook({ variables: { id: data.book._id } });
                                                }}>
                                                <Link to={`/edit/${data.book._id}`} className="btn btn-success">Edit</Link>&nbsp;
                                                <button type="submit" className="btn btn-danger">Delete</button>
                                            </form>
                                        {loading && <p>Loading...</p>}
                                        {error && <p>Error :( Please try again</p>}
                                        </div>
                                    )}
                                </Mutation>
                            </div>
                        </div>
                    </div>
                );
            }}
        </Query>
    );
  }
}

Finally, export this class name.

export default Show;

13. Create a Component to Add a New Book

To add a new Book, open and edit client/components/Create.js then add these imports.

import React, { Component } from 'react';
import gql from "graphql-tag";
import { Mutation } from "react-apollo";
import { Link } from 'react-router-dom';

Create a constant variable for the mutation.

const ADD_BOOK = gql`
    mutation AddBook(
        $isbn: String!,
        $title: String!,
        $author: String!,
        $description: String!,
        $publisher: String!,
        $published_year: Int!) {
        addBook(
            isbn: $isbn,
            title: $title,
            author: $author,
            description: $description,
            publisher: $publisher,
            published_year: $published_year) {
            _id
        }
    }
`;

Add a class with its contents like below.

class Create extends Component {

    render() {
      let isbn, title, author, description, published_year, publisher;
      return (
        <Mutation mutation={ADD_BOOK} onCompleted={() => this.props.history.push('/')}>
            {(addBook, { loading, error }) => (
                <div className="container">
                    <div className="panel panel-default">
                        <div className="panel-heading">
                            <h3 className="panel-title">
                                ADD BOOK
                            </h3>
                        </div>
                        <div className="panel-body">
                            <h4><Link to="/" className="btn btn-primary">Book List</Link></h4>
                            <form onSubmit={e => {
                                e.preventDefault();
                                addBook({ variables: { isbn: isbn.value, title: title.value, author: author.value, description: description.value, publisher: publisher.value, published_year: parseInt(published_year.value) } });
                                isbn.value = "";
                                title.value = "";
                                author.value = "";
                                description.value = "";
                                publisher.value = null;
                                published_year.value = "";
                            }}>
                                <div className="form-group">
                                    <label htmlFor="isbn">ISBN:</label>
                                    <input type="text" className="form-control" name="isbn" ref={node => {
                                        isbn = node;
                                    }} placeholder="ISBN" />
                                </div>
                                <div className="form-group">
                                    <label htmlFor="title">Title:</label>
                                    <input type="text" className="form-control" name="title" ref={node => {
                                        title = node;
                                    }} placeholder="Title" />
                                </div>
                                <div className="form-group">
                                    <label htmlFor="author">Author:</label>
                                    <input type="text" className="form-control" name="author" ref={node => {
                                        author = node;
                                    }} placeholder="Author" />
                                </div>
                                <div className="form-group">
                                    <label htmlFor="description">Description:</label>
                                    <textarea className="form-control" name="description" ref={node => {
                                        description = node;
                                    }} placeholder="Description" cols="80" rows="3" />
                                </div>
                                <div className="form-group">
                                    <label htmlFor="author">Publisher:</label>
                                    <input type="text" className="form-control" name="publisher" ref={node => {
                                        publisher = node;
                                    }} placeholder="Publisher" />
                                </div>
                                <div className="form-group">
                                    <label htmlFor="author">Published Year:</label>
                                    <input type="number" className="form-control" name="published_year" ref={node => {
                                        published_year = node;
                                    }} placeholder="Published Year" />
                                </div>
                                <button type="submit" className="btn btn-success">Submit</button>
                            </form>
                            {loading && <p>Loading...</p>}
                            {error && <p>Error :( Please try again</p>}
                        </div>
                    </div>
                </div>
            )}
        </Mutation>
      );
    }
}

Finally, export this class name.

export default Create;

14. Create a Component to Edit a Book

In the Show component, it’s a button that edit the Book. Now, we will create a component for edit a book. Open and edit client/components/Edit.js then add these imports.

import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import gql from "graphql-tag";
import { Query, Mutation } from "react-apollo";

Add a constant as a query to get the book data.

const GET_BOOK = gql`
    query book($bookId: String) {
        book(id: $bookId) {
            _id
            isbn
            title
            author
            description
            published_year
            publisher
            updated_date
        }
    }
`;

Add a constant as a mutation to update a book.

const UPDATE_BOOK = gql`
    mutation updateBook(
        $id: String!,
        $isbn: String!,
        $title: String!,
        $author: String!,
        $description: String!,
        $publisher: String!,
        $published_year: Int!) {
        updateBook(
        id: $id,
        isbn: $isbn,
        title: $title,
        author: $author,
        description: $description,
        publisher: $publisher,
        published_year: $published_year) {
            updated_date
        }
    }
`;

Add the class with the name Edit and it’s contents.

class Edit extends Component {

  render() {
    let isbn, title, author, description, published_year, publisher;
    return (
        <Query query={GET_BOOK} variables={{ bookId: this.props.match.params.id }}>
            {({ loading, error, data }) => {
                if (loading) return 'Loading...';
                if (error) return `Error! ${error.message}`;

                return (
                    <Mutation mutation={UPDATE_BOOK} key={data.book._id} onCompleted={() => this.props.history.push(`/`)}>
                        {(updateBook, { loading, error }) => (
                            <div className="container">
                                <div className="panel panel-default">
                                    <div className="panel-heading">
                                        <h3 className="panel-title">
                                            EDIT BOOK
                                        </h3>
                                    </div>
                                    <div className="panel-body">
                                        <h4><Link to="/" className="btn btn-primary">Book List</Link></h4>
                                        <form onSubmit={e => {
                                            e.preventDefault();
                                            updateBook({ variables: { id: data.book._id, isbn: isbn.value, title: title.value, author: author.value, description: description.value, publisher: publisher.value, published_year: parseInt(published_year.value) } });
                                            isbn.value = "";
                                            title.value = "";
                                            author.value = "";
                                            description.value = "";
                                            publisher.value = null;
                                            published_year.value = "";
                                        }}>
                                            <div className="form-group">
                                                <label htmlFor="isbn">ISBN:</label>
                                                <input type="text" className="form-control" name="isbn" ref={node => {
                                                    isbn = node;
                                                }} placeholder="ISBN" defaultValue={data.book.isbn} />
                                            </div>
                                            <div className="form-group">
                                                <label htmlFor="title">Title:</label>
                                                <input type="text" className="form-control" name="title" ref={node => {
                                                    title = node;
                                                }} placeholder="Title" defaultValue={data.book.title} />
                                            </div>
                                            <div className="form-group">
                                                <label htmlFor="author">Author:</label>
                                                <input type="text" className="form-control" name="author" ref={node => {
                                                    author = node;
                                                }} placeholder="Author" defaultValue={data.book.author} />
                                            </div>
                                            <div className="form-group">
                                                <label htmlFor="description">Description:</label>
                                                <textarea className="form-control" name="description" ref={node => {
                                                    description = node;
                                                }} placeholder="Description" cols="80" rows="3" defaultValue={data.book.description} />
                                            </div>
                                            <div className="form-group">
                                                <label htmlFor="author">Publisher:</label>
                                                <input type="text" className="form-control" name="publisher" ref={node => {
                                                    publisher = node;
                                                }} placeholder="Publisher" defaultValue={data.book.publisher} />
                                            </div>
                                            <div className="form-group">
                                                <label htmlFor="author">Published Year:</label>
                                                <input type="number" className="form-control" name="published_year" ref={node => {
                                                    published_year = node;
                                                }} placeholder="Published Year" defaultValue={data.book.published_year} />
                                            </div>
                                            <button type="submit" className="btn btn-success">Submit</button>
                                        </form>
                                        {loading && <p>Loading...</p>}
                                        {error && <p>Error :( Please try again</p>}
                                    </div>
                                </div>
                            </div>
                        )}
                    </Mutation>
                );
            }}
        </Query>
    );
  }
}

Finally, export the class name.

export default Edit;

15. Run and Test GraphQL CRUD from the React.js Application

Before running the whole application, make sure you have run the MongoDB server. To run the MongoDB server manually, type this command in the new Terminal tab.

mongod

Open the new terminal tab then type this command inside the project folder.

cd server
nodemon

Open the new terminal tab then type this command inside the project folder.

cd client
npm start

If asking to use a different port, just type Y. Now, the browser will automatically open then show the React.js and GraphQL application like these.

That it's, the Node, Express, React.js, Graphql, and MongoDB CRUD Web Application. You can find the full source code in our GitHub.

Thanks for reading ❤