DEV Community

Cover image for A Simple CRUD app With GraphQL, Apollo Server, MongoDB, and Express
FredAbod
FredAbod

Posted on

A Simple CRUD app With GraphQL, Apollo Server, MongoDB, and Express

A Simple CRUD app With GraphQL, Apollo Server, MongoDB, and Express

It has been said in some parts that learning GraphQL can be hard and complex to understand๐Ÿ˜Œ๐Ÿ˜Œ But thankfully ๐Ÿ˜‹๐Ÿ˜‹you have me to break it down to you.
In this tutorial I will be taking you step by step, we'll be creating a blog app where you can post the title and content of a blog, update the blog, and also get all blogs. I strongly believe that when you understand basic CRUD operations with these stacks you can build on the knowledge you have๐Ÿฅฐ..

Let's Dive right In

Dive

Step 1 Project Setup

Create a new directory for your project and initialize it with npm:

mkdir graphql-blog-app
cd graphql-blog-app
npm init -y
Enter fullscreen mode Exit fullscreen mode

Step 2: We'll Install Our Project Dependencies

npm install express mongoose graphql apollo-server-express
Enter fullscreen mode Exit fullscreen mode

Step 3: We'll Create Our Entry File, dotenv and gitignore file

touch index.js .env .gitignore
Enter fullscreen mode Exit fullscreen mode

Step 4: Let's edit our index.js file

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

const app = express();

// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/blog-app-graphql'); // Replace with your MongoDB connection string
mongoose.connection.once('open', () => {
  console.log('Connected to MongoDB');
});

// Use the `start` method to start the Apollo Server
async function startApolloServer() {
  await server.start();

  // Apply middleware after the server has started
  server.applyMiddleware({ app });

  const PORT = 3000; // Define the port for your Express server
  app.listen(PORT, () => {
    console.log(`Server listening on http://localhost:${PORT}${server.graphqlPath}`);
  });
}

// Start the Apollo Server
startApolloServer();
Enter fullscreen mode Exit fullscreen mode

Step 5: We're going to create our post models(Mongoose Schema). Create a models folder and a Post.js file and edit it

// models/Post.js
const mongoose = require('mongoose');

const postSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true,
  },
  content: {
    type: String,
    required: true,
  },
});

const Post = mongoose.model('Post', postSchema);

module.exports = Post;
Enter fullscreen mode Exit fullscreen mode

Step 6: Now we'll create our Graphql schema. so create a schema.js file

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

// Define the GraphQL schema using the gql template literal
const typeDefs = gql`
  # Post type represents a blog post
  type Post {
    id: ID!             # Unique identifier for the post
    title: String!      # Title of the post, non-nullable
    content: String!    # Content of the post, non-nullable
  }

  # Query type defines the available queries for fetching data
  type Query {
    posts: [Post]       # Query to get a list of all posts
    post(id: ID!): Post  # Query to get a specific post by ID
  }

  # Mutation type defines the available mutations for modifying data
  type Mutation {
    createPost(title: String!, content: String!): Post    # Mutation to create a new post
    updatePost(id: ID!, title: String, content: String): Post  # Mutation to update an existing post
    deletePost(id: ID!): Post                              # Mutation to delete a post
  }
`;

module.exports = typeDefs;
Enter fullscreen mode Exit fullscreen mode

I'll break it down a little further๐Ÿฅฐ

  1. Post Type:
    A "Post" is like a blog article.
    It has a unique ID, like a special number that is different for every post.
    It also has a title, which is like the name of the blog post.
    The content is what's written inside the blog post.
    Query:

  2. Think of a "Query" as a question you ask the computer to get information.
    We have two questions:

  3. "posts" asks for a list of all the blog posts.

  4. "post" asks for a specific blog post, and we need to tell the computer which one by giving it the post's special ID.
    Mutation:

  5. A "Mutation" is like giving the computer a task to change something.
    We have three tasks:

  6. "createPost" is like telling the computer to create a new blog post. We need to give it a title and content.

  7. "updatePost" is for changing the title or content of an existing blog post. We need to say which post (by its ID) and what we want to change.

  8. "deletePost" is for removing a blog post. Again, we need to tell the computer which post to delete.

Step 7: Now we'll create our resolvers, so you'll create resolvers.js file

// Import the Post model, assuming it's a file in the same directory
const Post = require('./models/Post');

// Resolvers define how to respond to GraphQL queries and mutations

const resolvers = {
  // Query resolver object handles read operations (fetching data)
  Query: {
    // Resolver for fetching all posts
    posts: async () => {
      try {
        // Use the Post model to find and return all posts
        return await Post.find();
      } catch (error) {
        // If there's an error, throw an informative error message
        throw new Error('Error fetching posts from the database');
      }
    },
    // Resolver for fetching a post by ID
    post: async (parent, { id }) => {
      try {
        // Use the Post model to find and return a specific post by ID
        return await Post.findById(id);
      } catch (error) {
        // If there's an error, throw an informative error message
        throw new Error(`Error fetching post with ID: ${id} from the database`);
      }
    },
  },

  // Mutation resolver object handles write operations (create, update, delete)
  Mutation: {
    // Resolver for creating a new post
    createPost: async (parent, { title, content }) => {
      try {
        // Create a new post instance using the Post model
        const post = new Post({ title, content });
        // Save the new post to the database and return it
        return await post.save();
      } catch (error) {
        // If there's an error, throw an informative error message
        throw new Error('Error creating a new post in the database');
      }
    },

    // Resolver for updating an existing post
    updatePost: async (parent, { id, title, content }) => {
      try {
        // Find and update a post by ID, return the updated post
        return await Post.findByIdAndUpdate(id, { title, content }, { new: true });
      } catch (error) {
        // If there's an error, throw an informative error message
        throw new Error(`Error updating post with ID: ${id} in the database`);
      }
    },

    // Resolver for deleting a post by ID
    deletePost: async (parent, { id }) => {
      try {
        // Find and delete a post by ID, return the deleted post
        return await Post.findByIdAndDelete(id);
      } catch (error) {
        // If there's an error, throw an informative error message
        throw new Error(`Error deleting post with ID: ${id} from the database`);
      }
    },
  },
};

// Export the resolvers for use in the Apollo Server
module.exports = resolvers;
Enter fullscreen mode Exit fullscreen mode

Step 8: Now we'll import our typedefs and resolvers into our index.js file

const express = require('express');
const { ApolloServer } = require('apollo-server-express');
const mongoose = require('mongoose');
const typeDefs = require('./schema'); // Import your GraphQL schema definition
const resolvers = require('./resolvers'); // Import your GraphQL resolvers

const app = express();

// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/blog-app-graphql'); // Replace with your MongoDB connection string
mongoose.connection.once('open', () => {
  console.log('Connected to MongoDB');
});

// Create an instance of ApolloServer with your schema and resolvers
const server = new ApolloServer({
  typeDefs,
  resolvers,
});

// Use the `start` method to start the Apollo Server
async function startApolloServer() {
  await server.start();

  // Apply middleware after the server has started
  server.applyMiddleware({ app });

  const PORT = 3000; // Define the port for your Express server
  app.listen(PORT, () => {
    console.log(`Server listening on http://localhost:${PORT}${server.graphqlPath}`);
  });
}

// Start the Apollo Server
startApolloServer();
Enter fullscreen mode Exit fullscreen mode

UUUUuuuhhhhhhhh and now we're done.. Now We TEST

uuggh

Step 9: We start the server

node index.js
Enter fullscreen mode Exit fullscreen mode

You should get this Server listening on http://localhost:3000/graphql
Connected to MongoDB

Now go to that route http://localhost:3000/graphql on your browser this would open up the Appolo server

You'll see the button Query Your Server
Let's create a post by making a mutation

mutation AddBlogMutation{
  createPost(title: "My Dev.to Blog", content: "My Dev Blog Content") {
    id
    title
    content
  }
}
Enter fullscreen mode Exit fullscreen mode

First Mutation

Let's update the post
We'll copy the id from the previous mutation

mutation updateBlog{
  updatePost(id: "65e946a3bf3014e3120fb1d8", title: "Dev Updated Title", content: "Dev Updated Content") {
    id
    title
    content
  }
}
Enter fullscreen mode Exit fullscreen mode

Update

Now let's get all post we make a posts query

query getAllPost{
  posts {
    id
    title
    content
  }
}
Enter fullscreen mode Exit fullscreen mode

Get All Post

Get Post Id

query getPostById{
  post(id: "65e6ccbcb42b8a669ac890e3") {
    id
    title
    content
  }
}
Enter fullscreen mode Exit fullscreen mode

Delete Post Mutation

mutation deleteMutation{
  deletePost(id: "65e6cc18b42b8a669ac890dd") {
    id
    title
    content
  }
}
Enter fullscreen mode Exit fullscreen mode

And now we're done๐Ÿ˜Ž๐Ÿ˜Ž๐Ÿ˜Ž. Isn't this interesting. I hope this article has been helpful. Here is the Github repo for the article...

Don't forget to hit the like ๐Ÿฅฐ๐Ÿฅฐ button and follow...

Bow

Top comments (1)

Collapse
 
hhnssl profile image
์˜คํ•œ์†”

Thank you so much. this is exactly What I need!