Well, this is the era of MERN stack , so why not learn it.
What is MERN
- M – Mern
- E – Express
- R – React
- N -Node
Don’t be happy , a lot of more package and plugin will be used , apart from above.
So let’s learn how to build a simple full stack application using all the above 4 tech stacks
Prerequisite
Basic knowledge of Java script ,React , Node Js will suffice
Note – I will try to explain as clearly as I can so that even if you don’t have any prior knowledge, it wont be overwhelming for you
Step 1 – Setup frontend and backend first
Create a folder – mern/frontend and mern/backend
Go to mern/frontend and start your react app
npx create-react-app .
Go to mern/backend and start you node js server
npm init
Step 2 – Create you first API
First let install few dependencies –
npm i express dotenv cors
npm install --save-dev nodemon
Now got to your package.json file –
Now write your first api –
server.js:
const express = require("express"); const app = express(); app.get("/", (req, res) => { res.send("api running"); }); app.listen(4000);
Hurray You ran your first API.
Step 3 – Install MongoDB locally
Download Link –
- MongoDB Community Edition – https://www.mongodb.com/try/download/community
- Mongodb shell – https://www.mongodb.com/try/download/shell
- Mongodb compass – https://www.mongodb.com/try/download/compass
How to install –
- First install MongoDB community edition to your program files
- Second Extra MongoDB shell to your C:// drive
- Now set environment variable for both –
And now restart your pc and go to cmd and type : mongosh
If something like this appears , congrats , its done.
Note – You can also install mongodb compass if you want GUI like interface.
Step 4 – Connect mongodb with nodejs
- Install mongoose package –
npm i mongoose
- Now to go to cmd and check if your mongodb server is running or not (type: mongosh)
- Create a .evn file and paste –
.env
PORT = 8000
URI = "mongodb://localhost:27017/demo2"
- Go to server.js and add –
//Connect to mongodb database(locally) const express = require("express"); const app = express(); const dotenv = require("dotenv"); const mongoose = require("mongoose"); dotenv.config(); mongoose .connect(process.env.URI) .then(() => { console.log("Connected Successfully"); app.listen(process.env.PORT || 5000, (err) => { if (err) console.log(err); console.log(`running at port ${process.env.PORT}`); }); }) .catch((error) => console.log("Failed to connect", error));
Step 5 – Create a schema and model
Model – It helps is interaction with the database
Schema – It define the structure on what type of data is going to be stored in our databsae
Create a model – mern/backend/models/userDataModel.js
userDataModel.js
const mongoose = require("mongoose"); //Create Schema const userDataSchema = new mongoose.Schema( { name: { type: String, required: true, }, email: { type: String, unique: true, required: true, }, age: { type: Number, }, }, { timestamps: true } ); //Create Model const userData = mongoose.model("UserData", userDataSchema); module.exports = userData;
Now import this in our main file i.e server.js
Note - As soon as we import our model , the database is created in the mongodb server.
The database name will be same, as we have pass in URI
In our case -
URI = "mongodb://localhost:27017/demo2"
So here the database name will be "demo2"
const express = require("express"); const app = express(); const dotenv = require("dotenv"); const mongoose = require("mongoose"); dotenv.config(); //model imported here const userData = require("./models/userDataModel"); app.get("/", (req, res) => { res.send("api running"); }); //Connect to mongodb database(locally) mongoose .connect(process.env.URI) .then(() => { console.log("Connected Successfully"); app.listen(process.env.PORT || 5000, (err) => { if (err) console.log(err); console.log(`running at port ${process.env.PORT}`); }); }) .catch((error) => console.log("Failed to connect", error)); app.listen(4000);
To test database is create or not , go to cmd and type : show dbs
Boom! Database created successfully.
Step 6 – Create Operation
Now lets create a new file for all our api’s .
Go to mern/backend/routes/userDataRoute.js
const express = require("express"); const router = express.Router(); const userData = require("../models/userDataModel"); //CREATE router.post("/", async (req, res) => { console.log(req.body); const { name, email, age } = req.body; try { const userAdded = await userData.create({ name: name, email: email, age: age, }); res.status(201).json(userAdded); } catch (error) { console.log(error); res.status(400).json({ error: error.message }); } }); module.exports = router;
Step 7 – Read Operation
//GET router.get("/", async (req, res) => { try { const allUsers = await userData.find(); res.status(200).json(allUsers); } catch (error) { res.status(500).json({ error: error.message }); } });
Get single user
//GET SINGLE USER router.get("/:id", async (req, res) => { const { id } = req.params; try { const singleUser = await userData.findById({ _id: id }); res.status(200).json(singleUser); } catch (error) { res.status(500).json({ error: error.message }); } });
Step 8 – Delete Operation
//DELETE router.delete("/:id", async (req, res) => { const { id } = req.params; try { const deletedUser = await userData.findByIdAndDelete({ _id: id }); res.status(201).json(deletedUser); } catch (error) { res.status(400).json({ error: error.message }); } });
Step 9 – Update Operation
Get single data
//UPDATE router.patch("/edit/:id", async (req, res) => { const { id } = req.params; console.log("get body", req.body); console.log("get id", id); //const { name, email, age } = req.body; try { const updatedUser = await userData.findByIdAndUpdate(id, req.body, { new: true, }); res.status(200).json(updatedUser); } catch (error) { res.status(400).json({ error: error.message }); } });
serves.js
const express = require("express"); const app = express(); const dotenv = require("dotenv"); const mongoose = require("mongoose"); dotenv.config(); const userDataRoute = require("./routes/userDataRoute"); app.use(express.json()); //Connect to mongodb database(locally) mongoose .connect(process.env.URI) .then(() => { console.log("Connected Successfully"); app.listen(process.env.PORT || 5000, (err) => { if (err) console.log(err); console.log(`running at port ${process.env.PORT}`); }); }) .catch((error) => console.log("Failed to connect", error)); app.use(userDataRoute);
Step 10 – Lets build frontend
First go to the folder – mern/frontend and type : npm start
Hurray! you react server is running.
Step 11 – Setting up Routing using react-router-dom
First install react router dom –
npm i react-router-dom
Now create a component folder : mern/frontend/src/components and create 3 react component
- Create.jsx (mern/frontend/src/components/Create.jsx)
- Read.jsx (mern/frontend/src/components/Read.jsx)
- Update.jsx (mern/frontend/src/components/Update.jsx)
Now go to App.js –
import "./App.css"; import { BrowserRouter, Route, Routes } from "react-router-dom"; import Create from "./components/Create"; import Read from "./components/Read"; import Update from "./components/Update"; import Navbar from "./components/Navbar"; function App() { return ( <div className="App"> <BrowserRouter> <Navbar /> <Routes> <Route exact path="/" element={<Create />} /> <Route path="/read" element={<Read />} /> <Route path="/:id" element={<Update />} /> </Routes> </BrowserRouter> </div> ); } export default App;
Step 12- Create form and submit data to backend
To perform our first operation i.e create, we need to form in frontend where user can fill the data and that will be passed to backend and finally stored in database.
Create.jsx
import React, { useState } from "react"; import { useNavigate } from "react-router-dom"; const Create = () => { const [fname, setName] = useState(""); const [email, setEmail] = useState(""); const [age, setAge] = useState(0); const [error, setError] = useState(""); const navigate = useNavigate(); const handleSubmit = async (e) => { e.preventDefault(); var addUser = { fname, email, age }; console.log(addUser); const response = await fetch("http://localhost:8000/", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(addUser), }); const result = await response.json(); if (!response.ok) { console.log(result.error); setError(result.error); } if (response.ok) { console.log(result); setName(""); setEmail(""); setAge(0); setError(""); navigate("/read"); } }; return ( <div class="container my-2"> <h1 class="h1 text-center">Fill the data</h1> {error && <div class="alert alert-danger"> {error} </div>} <form className="form" onSubmit={handleSubmit}> <div class="mb-3"> <label class="form-label">Name</label> <input type="text" class="form-control" value={fname} onChange={(e) => setName(e.target.value)} /> </div> <div class="mb-3"> <label class="form-label">Email address</label> <input type="email" class="form-control" value={email} onChange={(e) => setEmail(e.target.value)} /> </div> <div class="mb-3"> <label class="form-label">Age</label> <input type="number" class="form-control" value={age} onChange={(e) => setAge(e.target.value)} /> </div> <button type="submit" class="btn btn-primary"> Submit </button> </form> </div> ); }; export default Create;
Also, as soon as form is submitted, the page is navigated to read component ie. Read.jsx
Step 13 – Displaying all the data on the UI
Sample Structure to use –
import React from "react"; const Read = () => { return ( <div className="container my-2"> <div className="row"> <div className="col-3"> <div class="card"> <div class="card-body"> <h5 class="card-title">Card title</h5> <h6 class="card-subtitle mb-2 text-muted">Email</h6> <p class="card-text">age</p> <a href="#" class="card-link"> Edit </a> <a href="#" class="card-link"> Delete </a> </div> </div> </div> </div> </div> ); }; export default Read;
Read.jsx –
import React, { useEffect, useState } from "react"; const Read = () => { const [data, setData] = useState(); const [error, setError] = useState(); async function getData() { const response = await fetch("http://localhost:8000"); const result = await response.json(); console.log("result..", result); if (!response.ok) { setError(result.error); } if (response.ok) { console.log(response.ok); setData(result); setError(""); } } useEffect(() => { getData(); }, []); return ( <div className="container my-2"> {error && <div class="alert alert-danger"> {error} </div>} <div className="row"> {data?.map((ele) => ( <div key={ele._id} className="col-3"> <div class="card"> <div class="card-body"> <h5 class="card-title">{ele.name}</h5> <h6 class="card-subtitle mb-2 text-muted">{ele.email}</h6> <p class="card-text">{ele.age}</p> <span class="card-link">Edit</span> <span class="card-link">Delete</span> </div> </div> </div> ))} </div> </div> ); }; export default Read;
Step 14 – Deleting the data
Read.jsx
import React, { useEffect, useState } from "react"; const Read = () => { const [data, setData] = useState(); const [error, setError] = useState(); async function handleDelete(id) { const response = await fetch(`http://localhost:8000/${id}`, { method: "DELETE", }); const result1 = await response.json(); if (!response.ok) { setError(result1.error); } if (response.ok) { console.log("deleted", response.ok); setError("Deleted Successfully"); setTimeout(() => { setError(""); getData(); }, 1000); } } async function getData() { const response = await fetch("http://localhost:8000"); const result = await response.json(); console.log("result..", result); if (!response.ok) { setError(result.error); } if (response.ok) { setData(result); setError(""); } } useEffect(() => { getData(); }, []); return ( <div className="container my-2"> {error && <div class="alert alert-danger"> {error} </div>} <div className="row"> {data?.map((ele) => ( <div key={ele._id} className="col-3"> <div class="card"> <div class="card-body"> <h5 class="card-title">{ele.name}</h5> <h6 class="card-subtitle mb-2 text-muted">{ele.email}</h6> <p class="card-text">{ele.age}</p> <span class="card-link">Edit</span> <span class="card-link" onClick={() => handleDelete(ele._id)}> Delete </span> </div> </div> </div> ))} </div> </div> ); }; export default Read;
Step 15 – Updating User data from frontend
- First add link to update user button present in Read.jsx
- On clicking it should redirect to Update.jsx
- Now grab this id from the URL
- Create getSingleData() function to received a single user data and populate it on the input field
- Now create handleUpdate() function to send the updated data to the backend using PATCH/PUT request
- Grab the response
- Redirect to the Read.jsx
Update.jsx –
import React, { useEffect, useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; const Update = () => { const [fname, setName] = useState(""); const [email, setEmail] = useState(""); const [age, setAge] = useState(0); const [error, setError] = useState(); const { id } = useParams(); console.log(id); const navigate = useNavigate(); //receving single user data const getSingleData = async () => { const response = await fetch(`http://localhost:8000/${id}`); const result = await response.json(); if (response.ok) { setName(result.name); setEmail(result.email); setAge(result.age); } }; //passing edited data to backend const handleUpdate = async (e) => { e.preventDefault(); const updatedUser = { fname, email, age }; console.log(updatedUser); const response = await fetch(`http://localhost:8000/edit/${id}`, { method: "PATCH", headers: { "Content-Type": "application/json", }, body: JSON.stringify(updatedUser), }); const result = await response.json(); if (response.ok) { console.log("updated result..", result); setError(""); navigate("/read"); } if (!response.ok) { console.log(response.error); setError(response.error); } }; useEffect(() => { getSingleData(); }, []); return ( <div class="container my-2"> <h1 class="h1 text-center">Edit Data</h1> {error && <div class="alert alert-danger"> {error} </div>} <form className="form" onSubmit={handleUpdate}> <div class="mb-3"> <label class="form-label">Name</label> <input type="text" class="form-control" value={fname} onChange={(e) => setName(e.target.value)} /> </div> <div class="mb-3"> <label class="form-label">Email address</label> <input type="email" class="form-control" value={email} onChange={(e) => setEmail(e.target.value)} /> </div> <div class="mb-3"> <label class="form-label">Age</label> <input type="number" class="form-control" value={age} onChange={(e) => setAge(e.target.value)} /> </div> <button type="submit" class="btn btn-info"> Update </button> </form> </div> ); }; export default Update;
Step 16 – Adding Links of Navbar
Navbar.jsx
import React from "react"; import { Link } from "react-router-dom"; const Navbar = () => { return ( <nav className="navbar navbar-expand-lg navbar-light bg-light"> <div className="container-fluid"> <h3 className="navbar-brand" href="#"> MERN </h3> <button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation" > <span className="navbar-toggler-icon"></span> </button> <div className="collapse navbar-collapse" id="navbarNav"> <ul className="navbar-nav"> <li className="nav-item"> <Link to="/" className="nav-link" aria-current="page"> Create Post </Link> </li> <li className="nav-item"> <Link to="/read" className="nav-link active" aria-current="page"> All Post </Link> </li> </ul> </div> </div> </nav> ); }; export default Navbar;
Can i get the repository link for the project?
I’m getting CORS error after submit please help
the overall given good is not at all completed. You need to configure the cors, bootstap and bunch of other stuffs in create.jsx to make sure everything works smoothly. If you face difficulty in debugging do tell me, Ill post the complete code
please post the complete code or kindly provide your github link. It will be very helpful.
Can I have the complete code of this project sir