- Overview
- Features
- Tech Stack
- Screenshots
- Installation
- Usage
- Challenges & Lessons Learned
- Error Handling
- Deployment
- Contributing
- License
This is a full-stack MERN (MongoDB, Express.js, React, Node.js) application that implements a responsive contact form. Users can submit messages via a clean, intuitive frontend interface, which are securely stored in a MongoDB database through a RESTful backend API. Built with modern tools for rapid development, it emphasizes error handling, security, and user feedback.
The app demonstrates real-world practices like CORS configuration, environment variable management, Mongoose validation, and toast notifications for a seamless user experience.
- Form Validation: Client-side (React) and server-side (Mongoose) validation for name, email, subject, and message fields.
- Secure Submissions: JWT-ready auth structure (extendable); messages stored with timestamps and validation.
- Real-Time Feedback: Toast notifications for success/error states using React Hot Toast.
- Responsive Design: Tailwind CSS for mobile-first, accessible UI.
- API Endpoints:
POST /api/v1/message/send: Submit a new message.
- Admin View Potential: Easy extension for a dashboard to view/retrieve messages (e.g., via
GET /api/v1/message/all).
| Category | Technology | Version | Purpose | Documentation |
| --------------------- | ----------------------------------------------- | ------- | ---------------------------------------- | --------------------------------------------------------- |
| **Frontend** | [React](https://reactjs.org/) | 18+ | UI components and state management | [Docs](https://react.dev/) |
| | [Vite](https://vitejs.dev/) | 5.0+ | Fast bundling and hot module replacement | [Docs](https://vitejs.dev/guide/) |
| | [Axios](https://axios-http.com/) | 1.6+ | HTTP client for API calls | [Docs](https://axios-http.com/docs/intro) |
| | [React Hot Toast](https://react-hot-toast.com/) | 2.4+ | User-friendly notifications | [Docs](https://react-hot-toast.com/docs) |
| | [Tailwind CSS](https://tailwindcss.com/) | 3.3+ | Utility-first styling | [Docs](https://tailwindcss.com/docs/installation) |
| **Backend** | [Node.js](https://nodejs.org/) | 18+ | Server runtime environment | [Docs](https://nodejs.org/en/docs/) |
| | [Express.js](https://expressjs.com/) | 4.18+ | RESTful API framework | [Docs](https://expressjs.com/en/starter/hello-world.html) |
| | [MongoDB](https://www.mongodb.com/) | 4.4+ | NoSQL database for data storage | [Docs](https://www.mongodb.com/docs/) |
| | [Mongoose](https://mongoosejs.com/) | 8.0+ | MongoDB ODM with schema validation | [Docs](https://mongoosejs.com/docs/) |
| | [Cors](https://www.npmjs.com/package/cors) | 2.8+ | Enables cross-origin resource sharing | [Docs](https://www.npmjs.com/package/cors) |
| | [Dotenv](https://www.npmjs.com/package/dotenv) | 16.3+ | Environment variable management | [Docs](https://www.npmjs.com/package/dotenv) |
| **Development Tools** | [ESLint](https://eslint.org/) | — | Code linting and style enforcement | [Docs](https://eslint.org/docs/latest/) |
| | [Git](https://git-scm.com/) | — | Version control with GitHub integration | [Docs](https://git-scm.com/doc) |
| | [Postman](https://www.postman.com/) | — | API testing and debugging | [Docs](https://learning.postman.com/docs/) |
-
Clone the Repository:
git clone https://github.com/DevSars24/MERN2.git # Replace with your repo URL cd MERN2 -
Backend Setup:
cd backend npm install -
Frontend Setup:
cd ../frontend npm install -
Environment Configuration:
- Create
backend/config/config.env:PORT=4000 MONGO_URI="mongodb+srv://<username>:<password>@cluster0.mongodb.net/contactdb?retryWrites=true&w=majority" # Use your MongoDB Atlas URI FRONTEND_URL=http://localhost:5173 - For production, add
NODE_ENV=productionand secure your MONGO_URI.
- Create
-
Run the Application:
- Backend (in
backend/):node server.jsServer runs on
http://localhost:4000. - Frontend (in
frontend/):npm run devApp runs on
http://localhost:5173.
- Backend (in
- Open
http://localhost:5173in your browser. - Fill in the form fields: Name, Email, Subject, Message.
- Click Send Message.
- View toast notifications for feedback.
- Check MongoDB collection (
messages) or test API with Postman:POST http://localhost:4000/api/v1/message/send Content-Type: application/json { "name": "John Doe", "email": "john@example.com", "subject": "Inquiry", "message": "Hello, I have a question!" }
- CORS Configuration: Resolved by dynamically setting origins via
process.env.FRONTEND_URLand handling preflight OPTIONS requests explicitly. - Env Var Pathing: Fixed relative paths in
dotenv.config()to ensure loading from the correct directory—key for dev/prod parity. - MongoDB Integration: Ensured schema validation with required fields and custom error messages; tested connections with
mongoose.connection.on('error'). - Error Propagation: Custom try-catch blocks in controllers now bubble up Mongoose
ValidationErrordetails for precise frontend feedback. - Key Takeaway: Always test end-to-end (form → API → DB) early; tools like MongoDB Compass sped up debugging.
Robust error management ensures graceful failures:
- CORS:
app.use(cors({ origin: process.env.FRONTEND_URL || "http://localhost:5173", methods: ["GET", "POST", "PUT", "DELETE"], credentials: true, })); // Additional headers for preflights app.use((req, res, next) => { res.header("Access-Control-Allow-Origin", process.env.FRONTEND_URL || "http://localhost:5173"); res.header("Access-Control-Allow-Credentials", "true"); res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE"); res.header("Access-Control-Allow-Headers", "Content-Type"); next(); });
- Body Parsing:
app.use(express.json()); app.use(express.urlencoded({ extended: true }));
try {
const { name, email, subject, message } = req.body;
if (!name || !email || !subject || !message) {
return res.status(400).json({ success: false, message: "All fields are required!" });
}
await Message.create({ name, email, subject, message });
res.status(200).json({ success: true, message: "Message Sent Successfully!" });
} catch (error) {
if (error.name === "ValidationError") {
let errorMessage = Object.values(error.errors)
.map(err => err.message)
.join(" ");
return res.status(400).json({ success: false, message: errorMessage });
}
console.error("Server Error:", error); // Log for debugging
res.status(500).json({ success: false, message: "Server error. Please try again later." });
}try {
const res = await axios.post("http://localhost:4000/api/v1/message/send",
{ name, email, subject, message },
{ headers: { "Content-Type": "application/json" }, withCredentials: true }
);
toast.success(res.data?.message || "Message sent!");
// Reset form
setName(""); setEmail(""); setSubject(""); setMessage("");
} catch (error) {
const errorMsg = error?.response?.data?.message || "Something went wrong. Please try again.";
toast.error(errorMsg);
}-
Backend:
-
Frontend:
-
Full Stack:
- Update
FRONTEND_URLin backend env to production domain (e.g.,https://your-app.vercel.app). - Use MongoDB Atlas for cloud DB.
- Update
Pro Tip: Add a CI/CD pipeline with GitHub Actions for automated testing/linting on push.
- Fork the repo and create a feature branch (
git checkout -b feature/amazing-feature). - Commit changes (
git commit -m 'Add some amazing feature'). - Push to branch (
git push origin feature/amazing-feature). - Open a Pull Request—include tests and lint fixes.
- Run
npm run lintbefore submitting.
See CONTRIBUTING.md for detailed guidelines. Issues and stars welcome!
This project is licensed under the MIT License - see the LICENSE file for details.