A modern full-stack blog application built with Node.js, Express, MongoDB, and EJS templating engine. This application uses Fetch API for all CRUD operations, enabling proper RESTful methods (GET, POST, PUT, DELETE) without page reloads. Features a clean, responsive interface with real-time feedback.
- Features
- Technologies Used
- Prerequisites
- Installation
- Configuration
- Usage
- Project Structure
- API Routes
- Database Schema
- Contributing
- License
- Create Blog Posts: Write and publish blog posts with title and body content via Fetch API
- Update Blog Posts: Edit existing posts with pre-populated form using RESTful PUT method ✨ NEW!
- Delete Blog Posts: Remove posts with confirmation using RESTful DELETE method
- View All Posts: Browse all published blog posts on the homepage
- Individual Post View: Read full blog posts on dedicated pages
- RESTful API: Proper HTTP methods (GET, POST, PUT, DELETE) via Fetch API
- No Page Reloads: Smooth user experience with AJAX operations
- Real-time Feedback: Loading states and success/error messages
- About Page: Learn more about the blog
- Contact Page: Get in touch with the blog author
- Responsive Design: Mobile-friendly interface
- MongoDB Integration: Persistent storage for all blog posts
- EJS Templating: Dynamic content rendering with reusable components
-
Backend:
- Node.js
- Express.js ^4.21.1
- Mongoose ^8.8.1 (MongoDB ODM)
-
Frontend:
- EJS ^3.1.10 (Embedded JavaScript templating)
- HTML5
- CSS3
- Vanilla JavaScript (ES6+)
- Fetch API (RESTful AJAX operations)
-
Database:
- MongoDB
-
Dev Dependencies:
- Nodemon ^3.1.7 (Auto-restart development server)
Before you begin, ensure you have the following installed on your system:
-
Clone the repository (or download the project files):
git clone <repository-url> cd monBlogwithDB
-
Install dependencies:
npm install
-
Configure environment variables:
- Copy the example environment file:
cp .env.example .env
- Edit
.envand update the values as needed:NODE_ENV=development PORT=4000 MONGODB_URI=mongodb://localhost/my_blog DB_NAME=my_blog APP_NAME=My Blog
- Copy the example environment file:
-
Ensure MongoDB is running:
-
Start MongoDB service on your local machine:
# Windows net start MongoDB # macOS/Linux sudo systemctl start mongod
-
-
Start the application:
-
For development mode (with auto-restart on file changes):
npm run dev
-
For production mode:
npm start
-
-
Access the application:
- Open your browser and navigate to:
http://localhost:4000
- Open your browser and navigate to:
The application uses environment variables for configuration. Create a .env file in the root directory:
# Environment
NODE_ENV=development
# Server Configuration
PORT=4000
# Database Configuration
MONGODB_URI=mongodb://localhost/my_blog
DB_NAME=my_blog
# Application Configuration
APP_NAME=My BlogImportant: Never commit your .env file to version control. Use .env.example as a template.
The application connects to MongoDB using environment variables configured in your .env file:
// Configuration is centralized in src/config/config.js
const config = {
db: {
uri: process.env.MONGODB_URI || "mongodb://localhost/my_blog",
name: process.env.DB_NAME || "my_blog",
},
};To use a different database:
- Update
MONGODB_URIandDB_NAMEin your.envfile
The default port is 4000. To change it:
- Update the
PORTvariable in your.envfile
- Navigate to the "Create Post" page (
/create) - Fill in the following fields:
- Title: The title of your blog post
- Body: The main content of your post
- Click "Create Post" button
- The form is submitted via Fetch API (no page reload)
- You'll see a loading spinner and success message
- Automatically redirected to the homepage where your new post appears
Technical Details:
- Form submission intercepted by JavaScript
- Data sent as JSON to
POST /api/posts - Server returns JSON response with status
- Client-side JavaScript handles success/error feedback
- Navigate to any blog post (
/post/:id) - Click the "🗑️ Delete Post" button
- Confirm deletion in the popup dialog
- Post is deleted via Fetch API DELETE method
- Success message appears and you're redirected to homepage
Technical Details:
- Button click triggers JavaScript event handler
- Fetch API sends
DELETE /api/posts/:idrequest - Server deletes post and returns JSON confirmation
- No page reload - smooth user experience
- Navigate to any blog post (
/post/:id) - Click the "✏️ Edit Post" button
- Pre-populated form displays with current title and body
- Modify the content as needed
- Click "Update Post" button
- Post is updated via Fetch API PUT method
- Success message appears and you're redirected to the updated post
Technical Details:
- Click handler redirects to
/edit/:idpage route - Form displays current post data pre-filled
- Form submission sends
PUT /api/posts/:idrequest with updated data - Server updates post and returns JSON confirmation
- JavaScript redirects to post view page on success
- Shows loading spinner and error messages
- Homepage (
/): Displays all blog posts - Individual Post (
/post/:id): Click on any post to view its full content
- Home: View all blog posts
- About: Learn about the blog
- Contact: Contact information
- Create Post: Write a new blog post
monBlogwithDB/
├── index.js # Main application file (server setup)
├── package.json # Project dependencies and scripts
├── .env # Environment variables (not in git)
├── .env.example # Environment variables template
├── .gitignore # Git ignore rules
├── src/
│ ├── config/
│ │ └── config.js # Centralized configuration
│ ├── controllers/
│ │ ├── blogController.js # Blog post logic
│ │ └── pageController.js # Static page logic
│ ├── routes/
│ │ └── routes.js # Route definitions
│ ├── models/
│ │ └── BlogPost.js # Mongoose schema for blog posts
│ ├── views/
│ │ ├── index.ejs # Homepage template
│ │ ├── post.ejs # Individual post view template
│ │ ├── create.ejs # Create post form template
│ │ ├── edit.ejs # Edit post form template (NEW!)
│ │ ├── about.ejs # About page template
│ │ ├── contact.ejs # Contact page template
│ │ └── layouts/
│ │ ├── header.ejs # Reusable header component
│ │ ├── footer.ejs # Reusable footer component
│ │ ├── navbar.ejs # Navigation bar component
│ │ └── scripts.ejs # JavaScript includes
│ └── db.mjs # Database connection utilities
└── public/
├── css/
│ └── styles.css # Application styles
├── js/
│ ├── scripts.js # Bootstrap theme script
│ └── app.js # App-specific Fetch API handlers (NEW!)
└── assets/
└── img/ # Images and media files
These routes serve HTML pages for users to view in their browser:
| Method | Route | Description | Returns |
|---|---|---|---|
| GET | / |
Display all blog posts (homepage) | HTML |
| GET | /about |
Display about page | HTML |
| GET | /contact |
Display contact page | HTML |
| GET | /create |
Display create post form | HTML |
| GET | /edit/:id |
Display edit post form with pre-filled data | HTML |
| GET | /post/:id |
Display individual blog post by ID | HTML |
These routes handle data operations via Fetch API and return JSON responses:
| Method | Route | Description | Returns | Called By |
|---|---|---|---|---|
| POST | /api/posts |
Create and save a new post | JSON | Fetch API |
| PUT | /api/posts/:id |
Update an existing post | JSON | Fetch API |
| DELETE | /api/posts/:id |
Delete a post by ID | JSON | Fetch API |
Important Concept: This application separates page rendering from data operations.
- Purpose: Render HTML pages that users see
- Example: When you visit
/create, you see a form with input fields - Returns: Full HTML page with header, navbar, footer, etc.
- Usage: Direct browser navigation
- Purpose: Handle data operations (Create, Update, Delete)
- Example: When you submit the form, JavaScript sends data to
/api/posts - Returns: JSON response with success/error status
- Usage: Called by JavaScript Fetch API (AJAX)
- RESTful Design:
/api/*clearly indicates JSON endpoints - Separation of Concerns: HTML rendering vs data operations
- Modern Standard: Industry best practice for web applications
- Better UX: No page reloads, instant feedback
- Flexibility: Easy to build mobile apps or other clients using the same API
User clicks "Create Post" button
↓
Browser navigates to GET /create (page route)
↓
Server renders create.ejs with form
↓
User fills form and clicks "Submit"
↓
JavaScript intercepts form submission
↓
Fetch API sends POST to /api/posts (API route)
↓
Server processes data, returns JSON
↓
JavaScript receives response, shows message
↓
Redirect to homepage on success
{
title: String, // Title of the blog post
body: String, // Content of the blog post
username: {
type: String,
default: 'SuperDupont' // Default author name
},
datePosted: {
type: Date,
default: Date.now() // Automatically set to current date
}
}The project uses nodemon for automatic server restarts during development:
npm run devThis command runs nodemon index.js, which will automatically restart the server when you make changes to your files.
For production deployment, use:
npm startThis runs node index.js without automatic restarts.
npm start- Start the application in production modenpm run dev- Start the application in development mode with auto-restartnpm test- Run tests (not yet implemented)
If you encounter MongoDB connection errors:
- Ensure MongoDB is running:
mongod --version - Check if the MongoDB service is active
- Verify the connection string in
index.js
If port 4000 is already in use:
- Stop the process using port 4000, or
- Change the port number in
index.js
If you encounter package-related errors:
rm -rf node_modules package-lock.json
npm installContributions are welcome! Here's how you can help:
- Fork the project
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under the ISC License.
Created by SuperDupont
This application uses the modern Fetch API instead of traditional HTML form submissions, enabling:
-
Proper HTTP Methods:
- ✅ DELETE (not possible with HTML forms)
- ✅ PUT (not possible with HTML forms)
- ✅ POST with JSON payloads
- ✅ Custom headers
-
Better User Experience:
- No page reloads
- Loading indicators during operations
- Real-time success/error messages
- Smooth transitions
-
Code Example - Delete Post:
// Client-side (app.js)
const response = await fetch(`/api/posts/${postId}`, {
method: "DELETE",
headers: { "Content-Type": "application/json" },
});
const data = await response.json();
// Server-side (blogController.js)
export const deletePost = async (req, res) => {
const deletedPost = await BlogPost.findByIdAndDelete(req.params.id);
res.status(200).json({
success: true,
message: "Blog post deleted successfully",
});
};- Code Example - Update Post (NEW!):
// Client-side (app.js) - Form submission via Fetch
const response = await fetch(`/api/posts/${postId}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title, body }),
});
const data = await response.json();
// Server-side (blogController.js)
export const updatePost = async (req, res) => {
const updatedPost = await BlogPost.findByIdAndUpdate(
req.params.id,
req.body,
{ new: true, runValidators: true }
);
res.status(200).json({
success: true,
message: "Blog post updated successfully",
post: updatedPost,
});
};- Code Example - Create Post:
// Client-side (scripts.js)
const response = await fetch("/api/posts", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title, body, username }),
});
const data = await response.json();
// Server-side (blogController.js)
export const createPost = async (req, res) => {
const newPost = await BlogPost.create(req.body);
res.status(201).json({
success: true,
post: newPost,
});
};HTML Form Limitations:
- ❌ Only supports GET and POST methods
- ❌ Requires full page reload
- ❌ No loading states or progress indicators
- ❌ Cannot send JSON payloads
- ❌ Limited error handling
Fetch API Advantages:
- ✅ Supports all HTTP methods (GET, POST, PUT, DELETE, PATCH)
- ✅ No page reloads (better UX)
- ✅ Full control over requests and responses
- ✅ Native JSON support
- ✅ Promise-based (async/await)
- ✅ Better error handling
Potential features to add:
- ✅
Delete blog posts(Already implemented!) - ✅
Update/Edit blog posts(Already implemented!) - User authentication and authorization
- Image upload for blog posts
- Comments section
- Post categories and tags
- Search functionality
- Rich text editor
- Pagination for blog posts
- Admin dashboard
- Like/favorite posts
- Share to social media
Happy Blogging! 🎉