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
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
Step 2: We'll Install Our Project Dependencies
npm install express mongoose graphql apollo-server-express
Step 3: We'll Create Our Entry File, dotenv and gitignore file
touch index.js .env .gitignore
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();
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;
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;
I'll break it down a little furtherπ₯°
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:Think of a "Query" as a question you ask the computer to get information.
We have two questions:"posts" asks for a list of all the blog posts.
"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:A "Mutation" is like giving the computer a task to change something.
We have three tasks:"createPost" is like telling the computer to create a new blog post. We need to give it a title and content.
"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.
"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;
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();
UUUUuuuhhhhhhhh and now we're done.. Now We TEST
Step 9: We start the server
node index.js
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 mutationmutation AddBlogMutation{ createPost(title: "My Dev.to Blog", content: "My Dev Blog Content") { id title content } }
Let's update the post
We'll copy the id from the previous mutationmutation updateBlog{ updatePost(id: "65e946a3bf3014e3120fb1d8", title: "Dev Updated Title", content: "Dev Updated Content") { id title content } }
Now let's get all post we make a posts query
query getAllPost{ posts { id title content } }
query getPostById{ post(id: "65e6ccbcb42b8a669ac890e3") { id title content } }
Delete Post Mutation
mutation deleteMutation{ deletePost(id: "65e6cc18b42b8a669ac890dd") { id title content } }
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...
Top comments (1)
Thank you so much. this is exactly What I need!