Building a MERN (MongoDB, Express, React, Node.js) blogging platform from scratch is a great way to learn how to build full-stack applications. I'll walk you through the basic steps and key concepts, and by the end, you'll have a functional blogging platform!
Here's a high-level roadmap to building the blog platform:
1. Set Up the Development Environment
Before starting, make sure you have the following installed:
Node.js and npm (Node package manager)
MongoDB (You can use MongoDB Atlas for a cloud database if you don’t want to install MongoDB locally)
VS Code or any code editor you're comfortable with
2. Backend: Node.js + Express + MongoDB
We'll start by setting up the backend with Node.js, Express, and MongoDB. The backend will handle all the CRUD operations (Create, Read, Update, Delete) for the blog posts.
a. Initialize Node.js Project
mkdir mern-blog
cd mern-blog
npm init -y
b. Install Dependencies
We’ll need some packages for the backend:
npm install express mongoose cors dotenv body-parser
express: For the server
mongoose: For interacting with MongoDB
cors: To handle cross-origin requests (so React can talk to the backend)
dotenv: For environment variables
body-parser: To handle incoming JSON data
c. Create the Server (index.js)
Create a new file called index.js in the root directory and set up a basic Express server:
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
require('dotenv').config();
const app = express();
app.use(cors());
app.use(express.json());
// Connect to MongoDB
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('MongoDB connected'))
.catch((err) => console.log('Error connecting to MongoDB:', err));
// Define a basic route
app.get('/', (req, res) => {
res.send('Welcome to the MERN Blog!');
});
// Start the server
const port = process.env.PORT || 5000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
d. Create a .env File
Create a .env file to store sensitive information like your MongoDB URI:
MONGO_URI=your_mongodb_connection_string
e. Define Blog Post Model
Create a folder called models and add a BlogPost.js file to define the schema for the blog posts:
const mongoose = require('mongoose');
const blogPostSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
content: {
type: String,
required: true
},
author: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now
}
});
const BlogPost = mongoose.model('BlogPost', blogPostSchema);
module.exports = BlogPost;
f. Create Routes for CRUD Operations
In your index.js file, add the routes to handle the creation, reading, updating, and deleting of blog posts.
const BlogPost = require('./models/BlogPost');
// Create a new blog post
app.post('/api/posts', async (req, res) => {
try {
const { title, content, author } = req.body;
const newPost = new BlogPost({ title, content, author });
await newPost.save();
res.status(201).json(newPost);
} catch (err) {
res.status(400).json({ error: err.message });
}
});
// Get all blog posts
app.get('/api/posts', async (req, res) => {
try {
const posts = await BlogPost.find();
res.json(posts);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// Get a single blog post by ID
app.get('/api/posts/:id', async (req, res) => {
try {
const post = await BlogPost.findById(req.params.id);
if (!post) {
return res.status(404).json({ error: 'Post not found' });
}
res.json(post);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// Update a blog post
app.put('/api/posts/:id', async (req, res) => {
try {
const { title, content, author } = req.body;
const updatedPost = await BlogPost.findByIdAndUpdate(req.params.id, { title, content, author }, { new: true });
res.json(updatedPost);
} catch (err) {
res.status(400).json({ error: err.message });
}
});
// Delete a blog post
app.delete('/api/posts/:id', async (req, res) => {
try {
await BlogPost.findByIdAndDelete(req.params.id);
res.status(204).json({ message: 'Post deleted' });
} catch (err) {
res.status(500).json({ error: err.message });
}
});
3. Frontend: React
Now, let's build the front-end using React.
a. Create the React App
Inside the mern-blog folder, create the React application:
npx create-react-app client
cd client
npm start
b. Install Axios
We’ll use Axios to make HTTP requests to the backend API.
npm install axios
c. Create Blog Components
Create a components folder inside the src folder and add components for listing posts, creating new posts, and viewing individual posts.
App.js: The main component that will route to different parts of the application.
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import PostList from './components/PostList';
import CreatePost from './components/CreatePost';
import ViewPost from './components/ViewPost';
function App() {
return (
<Router>
<div className="App">
<Routes>
<Route path="/" element={<PostList />} />
<Route path="/create" element={<CreatePost />} />
<Route path="/post/:id" element={<ViewPost />} />
</Routes>
</div>
</Router>
);
}
export default App;
PostList.js: Display a list of all blog posts.
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
function PostList() {
const [posts, setPosts] = useState([]);
useEffect(() => {
axios.get('http://localhost:5000/api/posts')
.then(response => setPosts(response.data))
.catch(error => console.log(error));
}, []);
return (
<div>
<h1>Blog Posts</h1>
<Link to="/create">Create a New Post</Link>
<ul>
{posts.map(post => (
<li key={post._id}>
<Link to={`/post/${post._id}`}>{post.title}</Link>
</li>
))}
</ul>
</div>
);
}
export default PostList;
CreatePost.js: Form to create a new blog post.
import React, { useState } from 'react';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';
function CreatePost() {
const [title, setTitle] = useState('');
const [content, setContent] = useState('');
const [author, setAuthor] = useState('');
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
const newPost = { title, content, author };
try {
await axios.post('http://localhost:5000/api/posts', newPost);
navigate('/');
} catch (error) {
console.log(error);
}
};
return (
<div>
<h1>Create a New Post</h1>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Title"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<textarea
placeholder="Content"
value={content}
onChange={(e) => setContent(e.target.value)}
/>
<input
type="text"
placeholder="Author"
value={author}
onChange={(e) => setAuthor(e.target.value)}
/>
<button type="submit">Create Post</button>
</form>
</div>
);
}
export default CreatePost;
ViewPost.js: View the details of a single post.
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { useParams } from 'react-router-dom';
function ViewPost() {
const [post, setPost] = useState(null);
const { id } = use
Learn MERN Stack Training in Hyderabad
Read More
Building a Forum or Commenting System
Building a Fitness Tracker in MERN
Developing an E-commerce Site in MERN Stack
Visit Our Quality Thought Training Institute in Hyderabad
Subscribe by Email
Follow Updates Articles from This Blog via Email
No Comments