DEV Community

Cover image for GraphQL and MongoDB with React
Xen Beliaeva
Xen Beliaeva

Posted on

GraphQL and MongoDB with React

There is no permanent stop in the hunt for the best demonstration of development and functioning of web applications which is happening in web developer universe. A new and exciting technology that has just been recognized as a substitute for the older REST APIs is GraphQL. Different from what REST does in which it frequently returns a single data set for a single request, GraphQL can let clients request for specific data that they desire. Thus, it is a two-fold process as it not only reduces data transmission, but also speeds up and simplifies server-side responses. The combination of GraphQL and MongoDB yields a pair that is flexible and efficient in data handling. This marvelous combination of GraphQL and MongoDB is setting the stage for the revolution in the way developers design and manage dynamic web applications.

The Power of GraphQL

Great thing about GraphQL is its flexibility. Developers can optimize queries so that only one of them obtains all the data needed. This reduces the need for a total of a few subsequent requests to the REST API. This is very essential in current device heterogeneity and fluctuating network conditions.

With GraphQL, MongoDB, and React as the main tools for web development, these tools can now automate the development process. This makes it totally different. MongoDB, a document-oriented NoSQL database system, offers an excellent option to work with large volumes of unstructured information and is quite fast and flexible at querying GraphQL requests that are dynamic and not structured. Relying on the declaration-based nature of React for building user interfaces and handling the state of the application is very suitable. It complements the dynamic and robust nature of GraphQL by providing developers with live-flowing data from the database to the user interface.

In this article, we will go through the process of using GraphQL to communicate with MongoDB through React applications, how to set up a GraphQL server, how to integrate it with React and the best practices for optimizing database interaction. Thus, the union of these technologies minimizes programming time and simplifies the maintenance of the application, in addition to giving the chance to construct high-performance and scalable web applications.

GraphQL Basics

GraphQL, which was designed by the Facebook team in 2015, can be seen as a query language for your API, and at the same time, this query execution mechanism is powered by the data you have given. It allows companies to describe their API data completely and in a meaningful way so that their customers can ask them only for what they need exactly. This in turn, leads to the enhancement of the network and thus, the network load is reduced.

Schemas and types

The GraphQL schema is pivotal part of an API. The GraphQL schema defines the data types and the relationships between them, and so the queries are formed in such a way that they exactly match what the client is looking for. The description looks like a list, where the positions can have a type. They can also be a type of a type, what make it more flexible and complex data structures.

Queries

Unlike a collection of static attributes, queries in GraphQL can carry all data that correspond to the types provided in the schema, which are the result of specific applications’ needs. In the case of GraphQL, the clients are able to retrieve data in a way that exactly suits their needs without unnecessarily passing information, which is often the case in REST APIs.

An example query in GraphQL might look like this:

{
  user(id: "1") {
    name
    email
    friends {
      name
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

This query specifically asks for the user’s name, email and the names of their friends, excluding all other information about the user and their friends.

Mutations

Mutations in GraphQL are used to modify data. Just like queries, mutations are defined by the schema and allow clients to affect data in a precise and controlled way. A mutation can look like the following:

mutation {
  addUser(name: "John Doe", email: "john@example.com") {
    id
    name
    email
  }
}
Enter fullscreen mode Exit fullscreen mode

In this example, the addUser mutation adds a new user with the specified name and email address and returns information about the newly created user.

Subscriptions

Subscriptions stands out as a critical part of GraphQL as it offers the ability for clients to obtain real-time notifications about the data they’re eager to learn about. This is particularly helpful in those applications that need constant updates of the data, for instance, in chat rooms or games. Subscriptions in GraphQL can be implemented like this:

subscription {
  messageAdded(channelId: "1") {
    id
    content
    sender {
      name
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

When a new post is added to the channel, all subscribers will immediately receive a notification with the details of the post.

Comparison to REST

Instead of the concern that the server has towards determining the shape and the volume of the data as seen in REST, the client is in charge of actually asking the data in GraphQL which reduces the fetched data to be only what is required and also gives the client more control on how the interaction of data happens. This feature of GraphQL makes it perfect for the web applications of today that demand high performance and speed.

GraphQL server configuration
The first step in realizing the full potential of GraphQL in combination with MongoDB and React is to create a GraphQL server. In this section, we are going to learn how to create and run a server using this approach. The stack is made up of the front-end application with React and Apollo Client for GraphQL queries & mutations, and the back-end with Express and Apollo Server, and serverless Mongo DB through the Mongoose library.

Step 1: Personalize the project by addition of some install dependencies.
First, create a new node. first, open a new browser instance and navigate to the installation page where you need to perform the js project and then install the necessary packages. Open a terminal and run the following commands:

mkdir graphql-mongo-server
cd graphql-mongo-server
npm init -y
npm install apollo-server-express express graphql mongoose
Enter fullscreen mode Exit fullscreen mode

These commands will create a new directory for your project, initialize a new Node.js project, and install the necessary dependencies.

Step 2: Configure Express and Apollo Server
Create an index.js file and configure the underlying Express server and integrate Apollo Server to handle GraphQL queries

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

const app = express();
// Defining a GraphQL schema
const typeDefs = gql`
  type Query {
    hello: String
  }
`;
// Implementing resolvers
const resolvers = {
  Query: {
    hello: () => 'Hello, world!'
  }
};
// Create an Apollo server
const server = new ApolloServer({ typeDefs, resolvers });
// Applying Apollo middleware to Express
server.applyMiddleware({ app });
const PORT = 4000;
app.listen(PORT, () =>
  console.log(`Server is running at http://localhost:${PORT}${server.graphqlPath}`)
);
Enter fullscreen mode Exit fullscreen mode

Step 3: Connect MongoDB
Add MongoDB to the project using Mongoose. To do this, update the index.js file by adding the code to connect to the database:

const mongoose = require('mongoose');

// Connecting to MongoDB
mongoose.connect('mongodb://localhost:27017/mygraphqlapp', {
  useNewUrlParser: true,
  useUnifiedTopology: true
});
mongoose.connection.once('open', () => {
  console.log('Connected to MongoDB database');
});
Enter fullscreen mode Exit fullscreen mode

Replace localhost:27017/mygraphqlapp with your database connection string.

Step 4: Define GraphQL models and schema
Formalize the definition of the Mongoose data models and give permission to use the GraphQL schema with these models. For example, create a user model and add it to the GraphQL schema:

// Mongoose user model definition
const User = mongoose.model('User', new mongoose.Schema({
  name: String,
  email: String,
  age: Number
}));

// GraphQL schema extension
const typeDefs = gql`
  type User {
    id: ID!
    name: String
    email: String
    age: Int
  }
  type Query {
    users: [User]
  }
  type Mutation {
    addUser(name: String!, email: String!, age: Int): User
  }
`;
const resolvers = {
  Query: {
    users: () => User.find({})
  },
  Mutation: {
    addUser: async (_, { name, email, age }) => {
      const user = new User({ name, email, age });
      await user.save();
      return user;
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

These steps will create a basic GraphQL server with a MongoDB connection, ready to integrate with your React application. You can now use this server to process queries and mutations that interact efficiently with your database.

GraphQL integration with React

Having got your GraphQL server set, the other thing to do is the integration of that server with your React app. By means of Apollo Client, you can easily perform queries and mutations to your GraphQL server, which allows you to have a dynamic interaction with MongoDB data. In this case we will see how to add Apollo Client to React and look up some operations in this section.

Step 1: Install Apollo Client
Start by installing the necessary Apollo Client packages in your React project:

npm install @apollo/client graphql
Enter fullscreen mode Exit fullscreen mode

Step 2: Customize Apollo Client
Create an instance of Apollo Client and connect it to your React application. To do this, add the following code to a file such as ApolloClient.js:

import { ApolloClient, InMemoryCache, HttpLink, from } from '@apollo/client';

const httpLink = new HttpLink({
  uri: 'http://localhost:4000/graphql' // Replace with the URL of your GraphQL server
});
const client = new ApolloClient({
  cache: new InMemoryCache(),
  link: from([httpLink])
});
export default client;
Enter fullscreen mode Exit fullscreen mode

Step 3: Apollo Provider Integration
Wrap your React app in ApolloProvider so that queries and mutations can be available in any component of the app. In App.js:

import React from 'react';
import { ApolloProvider } from '@apollo/client';
import client from './ApolloClient';
import Users from './components/Users';

function App() {
  return (
    <ApolloProvider client={client}>
      <div className="App">
        <h1>GraphQL and React</h1>
        <Users />
      </div>
    </ApolloProvider>
  );
}
export default App;
Enter fullscreen mode Exit fullscreen mode

Step 4: Create and use queries and mutations
Create React components that use the useQuery and useMutation hooks to interact with GraphQL. Example of a component for displaying users and adding a new user:

import React, { useState } from 'react';
import { useQuery, useMutation, gql } from '@apollo/client';

const GET_USERS = gql`
  query {
    users {
      id
      name
      email
    }
  }
`;

const ADD_USER = gql`
  mutation AddUser($name: String!, $email: String!) {
    addUser(name: $name, email: $email) {
      id
      name
      email
    }
  }
`;

function Users() {
  const { data, loading, error } = useQuery(GET_USERS);
  const [addUser] = useMutation(ADD_USER);
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;
  const handleSubmit = async (event) => {
    event.preventDefault();
    if (name && email) {
      await addUser({ variables: { name, email } });
      window.location.reload(); // Simple page refresh after adding
    }
  };
  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          placeholder="Name"
          value={name}
          onChange={e => setName(e.target.value)}
        />
        <input
          type="email"
          placeholder="Email"
          value={email}
          onChange={e => setEmail(e.target.value)}
        />
        <button type="submit">Add User</button>
      </form>
      <ul>
        {data && data.users.map(user => (
          <li key={user.id}>{user.name} - {user.email}</li>
        ))}
      </ul>
    </div>
  );
}
export default Users;
Enter fullscreen mode Exit fullscreen mode

This code is an example of how to get data and send it to the server using GraphQL in a React application. The given example can be improved and generalized to match the more sophisticated needs and abilities of your application.

Real-life example: Todo app

Moving ahead, let’s create a To-Do application which is a standard exercise for beginners to learn the basics of web-development. In this particular section, we will build a simple Todo application, in which we’ll implement React as our frontend, use GraphQL for data management, and MongoDB for our data store. The project will cover the items such as the tasks creation, their editing and deleting.

Step 1: Configuring the MongoDB database
The first step is to set up MongoDB to store task data. Create a schema for the Todo items in MongoDB using Mongoose:

const mongoose = require('mongoose');

const { Schema } = mongoose;

const todoSchema = new Schema({
  text: String,
  completed: Boolean
});

const Todo = mongoose.model('Todo', todoSchema);
Enter fullscreen mode Exit fullscreen mode

Step 2: Create a GraphQL schema
Define a GraphQL schema that will include data types, queries, and mutations to manage Todo elements:

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

const typeDefs = gql`
  type Todo {
    id: ID!
    text: String!
    completed: Boolean!
  }
  type Query {
    todos: [Todo]
  }
  type Mutation {
    addTodo(text: String!): Todo
    updateTodo(id: ID!, completed: Boolean!): Todo
    deleteTodo(id: ID!): Todo
  }
`;
Enter fullscreen mode Exit fullscreen mode

Step 3: Implementing Resolvers
The next step is to implement the resolvers for GraphQL, which provide the logic for interacting with the database:

const resolvers = {
  Query: {
    todos: () => Todo.find({})
  },
  Mutation: {
    addTodo: async (_, { text }) => {
      const todo = new Todo({ text, completed: false });
      await todo.save();
      return todo;
    },
    updateTodo: async (_, { id, completed }) => {
      return Todo.findByIdAndUpdate(id, { completed }, { new: true });
    },
    deleteTodo: async (_, { id }) => {
      return Todo.findByIdAndRemove(id);
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

Step 4: Integrate with React via Apollo Client
Integrate Apollo Client into your React application and create components to display and manage tasks:

import React from 'react';
import { useQuery, useMutation, gql } from '@apollo/client';

const GET_TODOS = gql`
  query {
    todos {
      id
      text
      completed
    }
  }
`;

const ADD_TODO = gql`
  mutation AddTodo($text: String!) {
    addTodo(text: $text) {
      id
      text
      completed
    }
  }
`;

function Todos() {
  const { data, loading, error } = useQuery(GET_TODOS);
  const [addTodo] = useMutation(ADD_TODO);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  const handleAddTodo = async text => {
    if (text) {
      await addTodo({ variables: { text } });
    }
  };

  return (
    <div>
      <ul>
        {data.todos.map(todo => (
          <li key={todo.id}>
            {todo.text}
          </li>
        ))}
      </ul>
      <button onClick={() => handleAddTodo('New Todo')}>Add Todo</button>
    </div>
  );
}

export default Todos;`
Enter fullscreen mode Exit fullscreen mode

Step 5: Realizing the user interface
Develop a simple user-interface with React such that users can add, cross tasks off as completed and even delete tasks. You don’t have to use complex forms and buttons to organize your tasks.

The measures mentioned above will provide complete communication between your React application and GraphQL server with MongoDB as a data-base. This will produce an application that is fast and does its job.
Conclusion

Therefore, we have found a way to combine GraphQL, MongoDB and React. Combinations of these two can be real performance enhancers for web applications and significantly reduce the development complexity. Let’s look at some of the major points which makes this tech stack a priority.

Why use GraphQL?

  • Exactly as requested: GraphQL lets you request only the data you need, without the unnecessary data. This translates to less data ahead and faster page loading.
  • All through a single point: Say goodbye to a whole bunch of endpoints with REST APIs, GraphQL speaks through a single unified point which makes your code tractable and your architecture sober.
  • Real-time updates: With GraphQL, you can easily implement the functionality that is constantly updating the data — like chat or collaboration.

What exactly makes GraphQL so powerful?

  • Flexibility and power: MongoDB provides data storage flexibility, and on the other hand, React helps building user interfaces flexibility. As a team, they are a great combination that can effortlessly adjust to your every requirement.
  • Easier to develop: This stack will narrow down your code and boost the assurance with every development phase because of the clear rules of the GraphQL API.

Performance impact GraphQL and MongoDB
With GraphQL, React and MongoDB cooperation simplifies your life, and your applications become more responsive. Query optimization reduces server and network load, which in turn speeds up data processing and makes the interface more responsive. Hence, it is an important factor in improving the product quality in the eyes of the users.

In a nutshell, if you want to create more powerful web applications which are faster to run and easier to develop, the trio of GraphQL, MongoDB and React must be on your radar. It is a long-term investment in the future of your project that will certainly be profitable!

Please visit my site if you enjoyed the article!

Top comments (0)