MERN is a powerful full-stack framework that brings together four essential technologies for seamless web development.While React handles the frontend but, the real backbone of the backend is the connection between MongoDB, Express, and Node.
This blog unpacks how these components interact and their unique roles.
Consider a MERN stack project,which is structured as follows:
project-root/
├── client/ # Frontend (React)
└── server/ # Backend (Node.js + Express + MongoDB)
├── middleware/ # Handles authentication, logging, etc.
├── controllers/ # Processes business logic
├── routes/ # Defines API endpoints
├── models/ # Defines database schema
├── server.js # Entry point of the backend
How These Components Are Linked?
- Middleware(a function that has control over how the response is handled based on incoming requests.) is defined in server.js after initializing express framework.
- It then maps to routes( act as the URLs or links that process requests and direct them to the right place.), which define the API paths.
- Routes connect to controllers(manages the requests by determining which function should process a specific request.), which handle the logic of the request.
- Controllers interact with models(A user defined schema to based on client requirements), where the database schema is defined to store and manage data from the frontend.
Example
server.js
## Initializing express framework
const express = require('express');
const app = express(); // Initializes Express framework
##Middleware
app.use((req, res, next) => {
console.log(`Request received: ${req.method} ${req.url}`);
next(); // Passes control to the next middleware or route handler
});
const users = require("./routes/users");
app.use("/api/users", users);
Routing(routes/users.js)
const router = express.Router();
const userControllers = require("../controllers/userControllers");
router.post("/register", userControllers.register);
Controllers(controllers/userControllers.js)
const User = require("../models/User");
const register = async (req, res) => {
try {
const { username, email, password } = req.body;//destructured based on schema refernce
console.log(req.body);
if (existingUser) {
throw new Error("Email and username must be unique");
}
const user = await User.create({
username,
email,
password,
});
return res.json(user);
} catch (err) {
return res.status(400).json({ error: err.message });
}
};
module.exports = register; //which is fetched by routes as we imported there
model(models/User.js)
const mongoose = require("mongoose");
const { isEmail, contains } = require("validator");
const filter = require("../util/filter");
const UserSchema = new mongoose.Schema(
{
username: {
type: String,
required: true,
unique: true,
minlength: [6, "Must be at least 6 characters long"],
maxlength: [30, "Must be no more than 30 characters long"],
validate: {
validator: (val) => !contains(val, " "),
message: "Must contain no spaces",
},
},
email: {
type: String,
required: true,
unique: true,
validate: [isEmail, "Must be valid email address"],
},
password: {
type: String,
required: true,
minLength: [8, "Must be at least 8 characters long"],
}
},
{ timestamps: true }
);
next();
});//u can mention all constraints u want to add in a particular field based on the react registration form
module.exports = mongoose.model("user", UserSchema);//this helps to fetch this schema anywhere,when ever the import of the user is done like in controller section
To gain a clear understanding, let's backtrack our approach:
The model's export is imported into the controller, the controller's export followed in router, maintaining a structured hierarchy.
Conclusion
By understanding and implementing these components, you're well-equipped to create efficient and organized backend systems.
If you found this guide helpful drop a like.Feel free to reach out with any questions or topics you'd like to discuss.
For any further queries reach out to me at -
1.Linkedin
2.Github
Top comments (0)