How to Create a Mongodb GraphQL and React App

In this post we’re going to connect GraphQL, Mongo, and React together so you can have a React application query a GraphQL Server and return data from a MongoDB database.

Final Working Code

Note: the code in this tutorial will look a little different. In the repository I combined the front and back end into a single repository. Here I’m not going to do that in order to avoid non-critical code. We’re going to go a little faster in this post than in the videos too. So if you want a detailed and over-explained guide, please watch the videos.

Creating our GraphQL Server with Apollo-server-express

First, create a folder for your server, and an src/index.js inside.

run npm init -y to create a package.json file

Install the required packages with the following terminal command:

npm install apollo-server-core apollo-server-express dotenv express graphql mongoose

Step 1: Hello World GraphQL Server with apollo-server-express

We need the following code in src/index.js:

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

const app = express();

const typeDefs = gql`
  type Query {
    hello: String!
  }
`;

const resolvers = {
  Query: {
    hello: () => "Hello there I am a string!",
  },
};

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

const startServer = async () => {
  await server.start();

  server.applyMiddleware({ app });

  app.listen({ port: 4000 }, () =>
    console.log(
      `graphql server ready at http://localhost:4000${server.graphqlPath}`
    )
  );
};
startServer();

We’re creating an apollo server using apollo-server-express, so we need that along with the express package.

Then we store express() in the “app” const.

the typeDefs is where we store the schema. It’s basically like a blueprint for the server, which is called the “schema”. We use this to define all of the functions, their return values, and the parameters each function takes in. We’re also able to separate functions into Queries and Mutations. Queries retrieve data while mutations update and “mutate” data.

the resolvers is where the functions are actually defined. So the schema defines what the functions are named, what they return, and the parameters they take in, but the resolvers actually hold the functions themselves. Notice how in resolvers and typeDefs, they look almost the same.

An apolloserver needs the typeDefs and resolvers to work, so the const server holds the GraphQL server created by ApolloServer that we create in the code above.

Next we create a startServer function to actually start the server. We need to wait until the server is finished starting, which is why we have the async & await.

After calling server.start() we’ll want to “connect” or attach the GraphQL server (const server) to the express() server with server.applyMiddleware({ app });

Finally we can start up the entire server with app.listen(…)

Now visit http://localhost:4000/graphql and you’ll be greeted with some kind of landing page provided by Apollo. Click the “Query Your Server” button and it’ll take you to something like https://studio.apollographql.com/sandbox/explorer that looks like this:

You’ll notice we’re getting an error which is due to CORS. The GraphQL server needs to know which URLS are allowed to make requests. Our server doesn’t know that studio.apollographql.com is a friendly url. We need to let our server know by giving it the appropriate cors options. In src/index.js, insert the following code:

const app = express(); // this line already exists. Just here for reference.
const corsOptions = {
  credentials: true,
  origin: ["https://studio.apollographql.com"],
};

//...

server.applyMiddleware({ app, cors: corsOptions }); // line exists, but add cors: corsOptions

the corsOptions sets credentials to true, allowing for things like cookies to be sent back and forth between the client and server. It also sets the origin to an array of urls that are allowed to make requests to the server. We need studio.apollographql.com because that’s where we’ll be running queries for testing.

server.applyMiddleware is where we set the corsOptions to take effect.

Now we should be able to query our GraphQL server! In the apollo studio at localhost:4000/graphql, write out the following query and hit “run”, like the image below:

Sweet! We’re setup and ready for step #2: Connecting GraphQL to MongoDB

Step 2: Connecting GraphQL server to MongoDB

Create or login to your account at cloud.mongodb.com

Find the MongoDB projects area and create a new project. I’ll name mine “mongo-graphql-react-starter”:

And then click “next” and create project.

Finally, click Build a database.

I want to use the free version:

Choose whichever cloud provider you want, and the region closest to you. M0 is the free tier. I’m pretty sure you can only have one M0 per project, just an FYI.

Name the cluster and hit “create cluster” to create your MongoDB cluster.

Now it’ll take a few minutes to create.

Once the MongoDB cluster is finished creating, click “Connect”.

Allow Access from Anywhere (or add your list of ip addresses that can access mongo)

Add IP Address

Create a database user for this Mongo cluster. Remember the name and password!

Now “Choose a connection method” (didn’t bother with image). Just click the button.

Next click “Connect your application” and you should end up with a connection string dialog that looks like this:

That circled string above is what we’re going to use in the GraphQL api to connect to MongoDB. Pull mongoose into your GraphQL projects src/index.js file, then in the startServer() functjion we’ll run mongoose.connect AFTER starting the server. Like this:

const mongoose = require("mongoose"); // at top of file

// ...

const startServer = async () => {
  await server.start();

  server.applyMiddleware({ app, cors: corsOptions });

  await mongoose.connect(
    `mongodb+srv://john:Password1!@cluster0.yci0c.mongodb.net/my-mongo-project-db?retryWrites=true&w=majority`,
    {
      useNewUrlParser: true,
    }
  );

Take that string that you received from your Mongo dashboard and put it in the mongoose.connect call like you see above. Replace “john” with YOUR database user name, and Password1! with YOUR database user’s password.

Also swap out that /myFirstDatabase with /your-database-name.

Save the file and you should be connected.

Step 3: Test the MongoDB connection to GraphQL

Now we need to define the shape of our objects in MongoDB. We’ll use Mongoose models to do this. Create a file: /src/models/Post.js and put the following inside:

const mongoose = require("mongoose");

const Post = mongoose.model("Post", {
  author: String,
  content: String,
});

module.exports = {
  Post,
};

The code above basically says that the shape of our MongoDB objects are going to have an author and content properties. These are both going to be of type String, and they’re going to be accessible via the Post type. Then we export it so we can use all the functions like save(), find(), etc. on that type of collection in mongo.

Now we import the Post model into our src/index.js, and we can update our typeDefs and resolvers to query and mutate Post objects in Mongodb.

const { Post } = require("./models/Post");

//...

const typeDefs = gql`
  type Query {
    hello: String!
    posts: [Post!]!
  }

  type Mutation {
    createPost(author: String!, content: String!): Post!
  }

  type Post {
    id: ID!
    author: String!
    content: String!
  }
`;

const resolvers = {
  Query: {
    hello: () => "Hello there I am a string!",
    posts: async () => {
      const posts = await Post.find();

      return posts;
    },
  },
  
  Mutation: {
    createPost: (parent, args, context, info) => {
      const post = new Post({ author: args.author, content: args.content });

      return post.save();
    },
  },
};

Above, the typeDefs defines the queries and mutations. It says the “posts” resolver takes no arguments and returns an array of the type “Post”. The type “Post” is defined to have an id, author, and content property. There is one Mutation called “createPost” which takes two arguments “author” and “content” both of the type String. the createPost resolver must return a single instance of type Post.

the resolvers just declares and defines those functions required by typeDefs. You can see in the posts query we’re using Mongoose to find all the Post records in our Mongo database and returning them.

In the mutation we’re creating a post based off the arguments passed into the createPost mutation. At this point it’s just mongodb code in the resolvers. Now let’s run a mutation to create a post and see if the record gets saved in MongoDB. Go to your studio.apollographql and run the following query: (use the variables at the bottom to pass in your author and content. make sure the variables go between the { } brackets.) click the Run button to execute the mutation.

If the response returned an object that doesn’t look like an error, we can now go check MongoDB to see if the record has been saved in MongoDB. In MongoDB click “close”, then “browse collections”. If all is well, you should see the object we created in our Mongo Database:

Connect React to the GraphQL server (and fetch Mongo data!)

Create your react app with npx create-react-app ui or whatever you want to call your front end app.

CD into the directory and run the following command to install graphql and apollo client:

npm install @apollo/client graphql

in src/index.js:

import {
  ApolloClient,
  ApolloProvider,
  InMemoryCache,
  createHttpLink,
} from "@apollo/client";

const httpLink = createHttpLink({
  uri: "http://localhost:4000/graphql",
  credentials: "include",
});

const client = new ApolloClient({
  link: httpLink,
  cache: new InMemoryCache(),
});

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

In the code above we’re pulling in the packages we need.

The httpLink is basically a “Link” between the React front end and the Mongo + GraphQL server. In this case we’re “linking” to http://localhost:4000/graphql, aka our graphql api.

The “client” is where we make our client cache (InMemoryCache) and we use our link to the server.

Finally, we wrap the part of our app that needs access to the GraphQL queries and mutations. In this case, our entire app.

Then head over to the src/App.js and include the following code:

import "./App.css";
import { useQuery, gql } from "@apollo/client";

const POSTS_QUERY = gql`
  query {
    posts {
      id
      content
      author
    }
  }
`;

function App() {
  const { data, loading } = useQuery(POSTS_QUERY);

  if (loading) {
    return <div>Loading....</div>;
  }

  console.log("data: ", data);

  return (
    <div className="App">
      Hello React!
    </div>
  );

First we import useQuery and gql.

Then we create our query string and store it in POSTS_QUERY. this query gets all of our posts from the MongoDB database using the posts resolver in the GraphQL api.

the useQuery() function provided by Apollo provides a data and loading object which we can use. We also pass in the specific query that will run on the server.

If the “loading” state returned from the server is still “loading” then the app isn’t ready to display its content yet so we return “Loading…”.

Finally, the data gets stored in “data” and we can do whatever you want with it from there.

Unfortunately we get a CORS problem:

The problem here is that once again, our server does not allow http://localhost:3000 to interact with the GraphQL api. We need to give localhost:3000 permission to make requests to the server. We do that by updating the server’s src/index.js code with the following:

const corsOptions = {
  credentials: true,
  origin: ["https://studio.apollographql.com", "http://localhost:3000"],
};

Just like we had the problem with studio.apollographql.com in the beginning, it’s the same thing with our front end. Use the code above, save, and refresh the react app. We should be getting the posts back from our GraphQL server now:

That’s it! We’ve successfully connected MongoDB and React to a GraphQL Server, and we’re ready to build out our full stack application with React, MongoDB, and GraphQL.

Like this article?

Share on facebook
Share on Facebook
Share on twitter
Share on Twitter
Share on linkedin
Share on Linkdin
Share on pinterest
Share on Pinterest

Leave a Comment

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