In web development, creating a “Social Media Website” will showcase and utilising the power of MERN stack – MongoDB, Express, React, and Node. This application will provide users the functionality to add a post, like the post and able to comment on it.
Preview Image: Let us have a look at how the final output will look like.

Prerequisites:Approach to create Social Media Platform:- The social media website was developed with a dual focus on backend using Express.js and frontend using React.
- Express handled API routes for CRUD operations, including likes and comments, and Multer facilitated file uploads for multimedia content.
- React was chosen for the frontend, providing an interactive user interface with components for posts, likes, and comments.
- Axios played a pivotal role in connecting the frontend to the backend API endpoints, ensuring smooth communication.
- The integration phase involved configuring CORS, connecting frontend to backend API URLs, and thorough end-to-end testing for a seamless user experience.
Steps to Create the Project:Step 1: Create a directory for the backend by running the following command.
npm init social_backend cd social_backend Step 2: Initialize the Express project and install the following dependencies.
npm init -y npm install express mongoose cors body-parser multer uuid Folder Structure(Backend):
 The updated dependencies in package.json file of backend will look like:
"dependencies": { "body-parser": "^1.20.2", "cors": "^2.8.5", "express": "^4.18.2", "mongoose": "^8.0.3", "multer": "^1.4.5-lts.1", "uuid": "^9.0.1" } Example: Create the required files and add the following code:
JavaScript
// models/Post.js
const mongoose = require('mongoose');
const postSchema = new mongoose.Schema({
title: String,
content: String,
likes: { type: Number, default: 0 },
comments: [{ text: String }],
});
const Post = mongoose.model('Post', postSchema);
module.exports = Post;
JavaScript
// server.js
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cors = require('cors');
const multer = require('multer');
const path = require('path');
const app = express();
const PORT = process.env.PORT || 5000;
app.use(cors());
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/');
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
const upload = multer({ storage: storage });
mongoose.connect('Your MongoDB connection string', { useNewUrlParser: true, useUnifiedTopology: true });
const postSchema = new mongoose.Schema({
title: String,
content: String,
file: String,
likes: { type: Number, default: 0 },
comments: [{ text: String }],
});
const Post = mongoose.model('Post', postSchema);
app.use(bodyParser.json());
app.get('/api/posts', async (req, res) => {
try {
const posts = await Post.find();
res.json(posts);
} catch (error) {
res.status(500).json({ error: 'Internal Server Error' });
}
});
app.post('/api/posts', upload.single('file'), async (req, res) => {
try {
const { title, content } = req.body;
const file = req.file ? req.file.filename : undefined;
if (!title || !content) {
return res.status(400).json({ error: 'Title and content are required fields' });
}
const post = new Post({ title, content, file });
await post.save();
res.status(201).json(post);
} catch (error) {
console.error('Error creating post:', error);
res.status(500).json({ error: 'Internal Server Error' });
}
});
app.post('/api/posts/like/:postId', async (req, res) => {
try {
const postId = req.params.postId;
const post = await Post.findById(postId);
if (!post) {
return res.status(404).json({ error: 'Post not found' });
}
post.likes += 1;
await post.save();
res.json(post);
} catch (error) {
console.error('Error liking post:', error);
res.status(500).json({ error: 'Internal Server Error' });
}
});
app.post('/api/posts/comment/:postId', async (req, res) => {
try {
const postId = req.params.postId;
const { text } = req.body;
const post = await Post.findById(postId);
if (!post) {
return res.status(404).json({ error: 'Post not found' });
}
post.comments.push({ text });
await post.save();
res.json(post);
} catch (error) {
console.error('Error adding comment:', error);
res.status(500).json({ error: 'Internal Server Error' });
}
});
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
Step 3: To start the backend run the following command.
node server.js Step 4: Set up React frontend using the command.
npx create-react-app social_frontend cd social_frontend Step 5 : Installing the required packages:
npm i axios react-router-dom Folder Structure(Frontend):
 The updated dependencies in package.json file of frontend will look lik:
"dependencies": { "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "axios": "^1.6.5", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.21.1", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" } Example: Create the required files and the following code.
CSS
/* App.css */
.home {
max-width: 800px;
margin: 0 auto;
}
.post {
border: 1px solid #ddd;
padding: 15px;
margin-bottom: 20px;
}
.post h3 {
color: #333;
}
.post p {
color: #555;
}
/* App.css */
.create-post {
max-width: 600px;
margin: 20px auto;
padding: 20px;
border: 1px solid #ddd;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.create-post h2 {
color: #333;
}
.create-post input,
.create-post textarea {
width: 100%;
margin: 10px 0;
padding: 10px;
}
.create-post button {
background-color: #4caf50;
color: #fff;
padding: 10px 15px;
border: none;
cursor: pointer;
}
.comment-input {
margin-top: 10px;
padding: 8px;
width: 70%;
}
.comment-button {
background-color: #4caf50;
color: #fff;
padding: 8px 16px;
border: none;
cursor: pointer;
}
.post img,
.post video {
max-width: 100%;
height: auto;
margin-top: 10px;
}
.post button {
background-color: #4caf50;
color: #fff;
padding: 8px 16px;
border: none;
cursor: pointer;
margin-right: 10px;
}
.post ul {
list-style: none;
padding: 0;
}
.post li {
margin-bottom: 5px;
}
.comment-input {
margin-top: 10px;
padding: 8px;
width: 70%;
}
.comment-button {
background-color: #4caf50;
color: #fff;
padding: 8px 16px;
border: none;
cursor: pointer;
}
/* App.css */
.app {
max-width: 800px;
margin: 0 auto;
}
nav {
background-color: #333;
padding: 10px;
}
nav ul {
list-style: none;
margin: 0;
padding: 0;
}
nav li {
display: inline-block;
margin-right: 20px;
}
nav a {
text-decoration: none;
color: #fff;
font-weight: bold;
font-size: 16px;
}
nav a:hover {
color: #4caf50;
}
.create-post,
.home {
border: 1px solid #ddd;
padding: 20px;
margin-bottom: 20px;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.home h2,
.create-post h2 {
color: #333;
}
.home .post,
.create-post {
margin-bottom: 30px;
}
.home .post button,
.create-post button {
background-color: #4caf50;
color: #fff;
padding: 10px 15px;
border: none;
cursor: pointer;
}
.home .post button:hover,
.create-post button:hover {
background-color: #45a049;
}
JavaScript
// App.js
import React from 'react';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
import Home from './Home';
import CreatePost from './CreatePost';
import './App.css';
function App() {
return (
<Router>
<div className="app">
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/create">Create Post</Link>
</li>
</ul>
</nav>
<Routes>
<Route path="/create" element={<CreatePost />} />
<Route path="/" element={<Home />} />
</Routes>
</div>
</Router>
);
}
export default App;
JavaScript
// Home.js
import React, { useState, useEffect } from "react";
import axios from "axios";
function Home() {
const [commentInput, setCommentInput] = useState("");
const [posts, setPosts] = useState([]);
useEffect(() => {
axios
.get("http://localhost:5000/api/posts")
.then((response) => setPosts(response.data))
.catch((error) => console.error("Error fetching posts:", error));
}, []);
const handleLike = (postId) => {
axios
.post(`http://localhost:5000/api/posts/like/${postId}`)
.then((response) => {
const updatedPosts = posts.map((post) =>
post._id === postId ? response.data : post
);
setPosts(updatedPosts);
})
.catch((error) => console.error("Error liking post:", error));
};
const handleAddComment = (postId, commentText) => {
axios
.post(`http://localhost:5000/api/posts/comment/${postId}`, {
text: commentText,
})
.then((response) => {
const updatedPosts = posts.map((post) =>
post._id === postId ? response.data : post
);
setPosts(updatedPosts);
})
.catch((error) => console.error("Error adding comment:", error));
};
return (
<div className="home">
<h2>Recent Posts</h2>
{posts.map((post) => (
<div key={post._id} className="post">
<h3>{post.title}</h3>
<p>{post.content}</p>
{post.file && (
<div>
{post.file.includes(".mp4") ? (
<video width="320" height="240" controls>
<source
src={
`http://localhost:5000/uploads/${post.file}`
}
type="video/mp4"
/>
Your browser does not support the video tag.
</video>
) : (
<img
src={
`http://localhost:5000/uploads/${post.file}`
}
alt="Post Media"
/>
)}
</div>
)}
<p>Likes: {post.likes}</p>
<button onClick={() => handleLike(post._id)}>Like</button>
<p>Comments: {post.comments.length}</p>
<ul>
{post.comments.map((comment, index) => (
<li key={index}>{comment.text}</li>
))}
</ul>
<input
type="text"
placeholder="Add a comment"
className="comment-input"
onChange={(e) => setCommentInput(e.target.value)}
/>
<button
onClick={() => handleAddComment(post._id, commentInput)}
className="comment-button"
>
Add Comment
</button>
</div>
))}
</div>
);
}
export default Home;
JavaScript
// CreatePost.js
import React, { useState } from "react";
import axios from "axios";
function CreatePost() {
const [newPost, setNewPost] = useState({
title: "",
content: "",
file: null,
});
const handleInputChange = (event) => {
const { name, value } = event.target;
setNewPost({ ...newPost, [name]: value });
};
const handleFileChange = (event) => {
setNewPost({ ...newPost, file: event.target.files[0] });
};
const handlePostSubmit = () => {
const formData = new FormData();
formData.append("title", newPost.title);
formData.append("content", newPost.content);
formData.append("file", newPost.file);
axios
.post("http://localhost:5000/api/posts", formData)
.then((response) => {
setNewPost({ title: "", content: "", file: null });
})
.catch((error) => console.error("Error creating post:", error));
};
return (
<div className="create-post">
<h2>Create a Post</h2>
<input
type="text"
name="title"
placeholder="Title"
value={newPost.title}
onChange={handleInputChange}
/>
<textarea
name="content"
placeholder="Content"
value={newPost.content}
onChange={handleInputChange}
></textarea>
<input type="file" name="file" onChange={handleFileChange} />
<button onClick={handlePostSubmit}>Post</button>
</div>
);
}
export default CreatePost;
Step 6: Start the application by running the following command.
npm start Output:
|