Education
Software Development Executive - I
Last updated on Aug 9, 2024
Last updated on Jan 27, 2024
The MERN stack is an acronym for MongoDB, Express.js, React, and Node.js. It's a powerful combination of technologies that allows developers to build a full-stack application with a single language - JavaScript. This unified language across the client and server-side simplifies development and allows for a more streamlined workflow.
The MERN stack is a modern web development framework integrating four key technologies to create dynamic and scalable applications. Let's break down the role of each component in the stack:
MongoDB: A NoSQL database, MongoDB stores data in a flexible, JSON-like format. MongoDB can easily handle vast amounts of data and complex operations. It's the backbone of our data persistence layer, and understanding how to interact with the MongoDB database is crucial for MERN stack developers.
Express.js: This minimal and flexible Node.js web application framework provides robust features to develop web and mobile applications. It simplifies writing server code, handling HTTP requests, and interacting with the MongoDB database.
React: A front-end library is used for building user interfaces, particularly single-page applications where you need a fast, interactive user experience. Each React app comprises components that manage their state and compose to form complex UIs.
Node.js: As the runtime environment for executing JavaScript code server-side, Node.js allows us to build scalable network applications. The engine powers our server, allowing us to use JavaScript to write command-line tools and server-side scripting.
Before diving into coding, we must set up our development environment. This involves installing Node.js, which comes with npm (Node Package Manager), and MongoDB. We'll also install the create-react-app utility to scaffold our React application.
Install Node.js and npm: Visit the Node.js website and download the installer for your operating system. This will also install npm, which is essential for managing JavaScript packages.
Install MongoDB: You have two options: install MongoDB locally on your machine or use MongoDB Atlas, a cloud-based MongoDB service. For local installation, follow the instructions on the MongoDB website. If you prefer using MongoDB Atlas, sign up and create a new cluster on the MongoDB Atlas website.
Install create-react-app: With npm installed, you can now install create-react-app globally on your machine using the command line. This utility helps you to quickly create a new React project with all the necessary configurations.
npm install -g create-react-app
Create a New React App: Navigate to the directory where you want your project folder to be, and run the following command to create a new React app:
create-react-app my-react-app
Replace my-react-app with your desired project name. This will create a new folder with all the React scripts and a src folder where you can start writing your React code.
Running the React App: To make sure everything is set up correctly, navigate to your React project folder in the command line and run:
npm start
This command will start the development server, typically at http://localhost:3000, and open your new React app in the browser. You should see the default landing page provided by create-react-app.
After creating your React app, it's essential to understand the structure of the project folder. The create-react-app tool generates a React project with a sensible default structure:
Within the src folder, you'll find the following essential files:
With these steps completed, your development environment is now ready. You can begin developing your React components, setting up Express.js as your server, and connecting everything to your MongoDB database.
The choice of database is critical in any full-stack application, and MongoDB offers a flexible, scalable solution for storing and managing data. Whether you install MongoDB locally or use MongoDB Atlas, the cloud-based service, you'll need to understand how to set up and connect to your MongoDB database to store data effectively.
There are two main ways to set up MongoDB for your project: installing it locally on your machine or using MongoDB Atlas, the cloud service provided by MongoDB.
Installing MongoDB Locally: For developers who prefer to have the database running on their machine, installing MongoDB locally is the way to go.
Download MongoDB Community Server: Navigate to the MongoDB Download Center and choose the version compatible with your operating system. Download the installer package.
Install MongoDB: Run the downloaded installer and follow the installation wizard's instructions. The installer typically includes MongoDB Compass, a database GUI that can be optionally installed.
Set Up the Data Directory: MongoDB expects a data directory at /data/db on your root directory by default. You can create this directory using the following command in your command line or terminal:
For Unix systems (Linux/Mac):
1sudo mkdir -p /data/db 2sudo chown `id -u` /data/db 3
When starting MongoDB, you can manually create a C:\data\db
folder or specify a different data directory for Windows.
Start the MongoDB Server: To start the MongoDB server, run the mongod process. If you've set up the default data directory, you can run:
1mongod 2
If you're using a custom data directory, you'll need to specify it with the --dbpath option:
1mongod --dbpath your-custom-path 2
Verify the Installation: To ensure that MongoDB is installed and running correctly, you can connect to the database using the mongo shell. Type mongo in a new command line or terminal window and press Enter. This will connect to the default test database. If you see the MongoDB shell prompt, your installation is successful.
Interact with MongoDB: You can start interacting with your MongoDB database with the Mongo shell. Create databases, collections, and documents, and perform operations like insert, find, update, and delete.
Using MongoDB Atlas: MongoDB Atlas is a fully-managed cloud database service that handles the complexities of deploying, managing, and healing your deployments. It offers benefits like scalability, high availability, and geographic distribution. To use MongoDB Atlas, you'll need to:
Both options have their advantages. The local installation allows for easy development and testing without an internet connection. At the same time, MongoDB Atlas offers a robust, scalable solution without the need to maintain and update your own MongoDB server.
Once your MongoDB server is set up locally or on Atlas, you'll need to configure your application to connect to it. This is done using a MongoDB connection string, a URL specifying your database's location and how to connect to it.
Here's an example of what a MongoDB connection string might look like for a local installation:
1const mongoose = require('mongoose'); 2 3mongoose.connect('mongodb://localhost:27017/mydatabase', { 4 useNewUrlParser: true, 5 useUnifiedTopology: true 6}); 7
And for a MongoDB Atlas connection:
1const mongoose = require('mongoose'); 2 3const atlasConnectionString = 'your-atlas-connection-string-goes-here'; 4mongoose.connect(atlasConnectionString, { 5 useNewUrlParser: true, 6 useUnifiedTopology: true 7}); 8
In both cases, we're using Mongoose, an object data modeling (ODM) library for MongoDB and Node.js, which makes managing relationships between data and translating between objects in code and their representation in MongoDB easier.
Remember to replace 'your-atlas-connection-string-goes-here' with the actual connection string provided by MongoDB Atlas. This string will contain your username, password, and the database name you wish to connect to. It's also a best practice to store your connection string in an environment variable rather than hardcoding it into your application. This can be done using a .env file in your project's root directory:
DB_CONNECTION_STRING=your-actual-connection-string
And then in your code, you would use:
1require('dotenv').config(); 2const mongoose = require('mongoose'); 3 4mongoose.connect(process.env.DB_CONNECTION_STRING, { 5 useNewUrlParser: true, 6 useUnifiedTopology: true 7}); 8
By calling dotenv.config(), you load the environment variables from your .env file into process.env, making them accessible throughout your application.
Once connected, you should handle the connection events to manage the connection lifecycle properly:
1mongoose.connection.on('connected', () => { 2 console.log('MongoDB database connection established successfully'); 3}); 4 5mongoose.connection.on('error', (err) => { 6 console.error('MongoDB database connection error:', err); 7}); 8
With the MongoDB database successfully connected, you can define your data models using Mongoose schemas and start interacting with your database from your Node.js application.
Creating a back-end server is fundamental in full-stack development, especially when working with the MERN stack. Node.js is the runtime environment hosting our server, allowing us to use JavaScript on the back end. With Node.js, we can build a fast, scalable server capable of handling numerous connections simultaneously.
We first need to initialize a new Node.js project to start building our back-end server. This is done using the npm init command, which creates a package.json file in our project folder. This file will keep track of our project's dependencies and scripts. Here's how to get started:
Create a New Project Folder: If you haven't already, create a new folder for your back-end server. This can be separate from your React client or part of the same project folder if you're building a monorepo.
Initialize the Node.js Project: Open your command line, navigate to your project folder, and run:
1npm init -y 2
The -y flag will automatically fill in the default values for your package.json file.
Install Express.js: Express.js is a minimal web application framework for Node.js that simplifies the server creation process. Install it by running:
1npm install express 2
Create the Server File: In your project folder, create a new file named server.js or app.js, which will be the entry point for your server.
Set Up Express.js: Open the server file you just created and set up a basic Express server:
1const express = require('express'); 2const app = express(); 3 4app.use(express.json()); 5 6const port = process.env.PORT || 3001; 7 8app.listen(port, () => { 9 console.log(`Server is running on port ${port}`); 10}); 11
In this code snippet, we import Express, create an Express app, and set it to listen on a specified port. We also use express.json() middleware to parse JSON payloads from incoming requests.
With the Express server initialized, the next step is to connect it to our MongoDB server. Whether you're using a local MongoDB instance or MongoDB Atlas, you'll need to configure the connection using Mongoose, an ODM library that simplifies interactions with our MongoDB database.
Install Mongoose: Add Mongoose to your project by running:
1npm install mongoose 2
Connect to MongoDB: In your server file typically server.js or app.js, add the following code to connect to your MongoDB database using Mongoose:
1const mongoose = require('mongoose'); 2 3const dbConnectionString = process.env.MONGODB_URI || 'mongodb://localhost:27017/mydatabase'; 4 5mongoose.connect(dbConnectionString, { 6 useNewUrlParser: true, 7 useUnifiedTopology: true 8}); 9 10mongoose.connection.on('connected', () => { 11 console.log('Successfully connected to MongoDB database'); 12}); 13 14mongoose.connection.on('error', (err) => { 15 console.error('MongoDB connection error:', err); 16}); 17
Replace 'mongodb://localhost:27017/mydatabase' with your actual MongoDB connection string. If you're using MongoDB Atlas, replace it with the connection string provided by Atlas.
Environment Variables: Store your MongoDB connection string in an environment variable for security and flexibility. To manage these variables, you can use a .env file in your project's root directory. Make sure to install the dotenv package to load these variables into your application:
1npm install dotenv 2
Then, at the top of your server file, add:
1require('dotenv').config(); 2
And update your connection string to use the environment variable:
1const dbConnectionString = process.env.MONGODB_URI; 2
With these steps, your Node.js server is initialized with Express.js and connected to your MongoDB database.
A Mongoose schema defines the document's structure, default values, validators, etc. Here's how you can specify a schema and a model for a simple user:
Create a Schema: Define the schema for the data you want to store in MongoDB. For example, if you're creating a user model, your schema might include a name, email, and password:
1const mongoose = require('mongoose'); 2 3const userSchema = new mongoose.Schema({ 4 name: { 5 type: String, 6 required: true 7 }, 8 email: { 9 type: String, 10 required: true, 11 unique: true 12 }, 13 password: { 14 type: String, 15 required: true 16 } 17}); 18
Create a Model: Once you have a schema, you can create it by passing it into mongoose.model. The first argument is the singular name of the collection your model is for, and Mongoose will automatically look for the plural version of your model name:
1const User = mongoose.model('User', userSchema); 2
Interact with the Model: With the model in place, you can now create, read, update, and delete documents using standard Mongoose methods. For example, to create a new user, you would do the following:
1const newUser = new User({ 2 name: 'John Doe', 3 email: 'john@example.com', 4 password: 'password123' 5}); 6 7newUser.save(function(err) { 8 if (err) return console.error(err); 9 console.log('User created successfully'); 10}); 11
By defining schemas and models, you create a blueprint for how your data should be structured and manipulated within the MongoDB database. This structure is crucial for maintaining data integrity and consistency across your application.
With the back-end server and database connection established, the next step in building our full-stack application is to create REST API endpoints. These endpoints will bridge the React client and the MongoDB database, allowing for data creation, reading, updating, and deletion through HTTP requests.
RESTful APIs follow a standard methodology using HTTP requests to interact with data. The four main types of operations we'll implement are CRUD: Create, Read, Update, and Delete. Each operation corresponds to an HTTP method: POST for create, GET for read, PUT or PATCH for update, and DELETE for delete.
Create (POST): We'll use the POST method to create a new resource, such as a user or a post. Here's an example of how to set up a POST endpoint to create a new user:
1const express = require('express'); 2const User = require('./models/User'); // Assuming you have a User model defined 3const app = express(); 4 5// POST endpoint to create a new user 6app.post('/users', async (req, res) => { 7 try { 8 const newUser = new User(req.body); 9 await newUser.save(); 10 res.status(201).send(newUser); 11 } catch (error) { 12 res.status(400).send(error); 13 } 14}); 15
Read (GET): We use the GET method to retrieve resources. This can be for fetching a single item or a list of items. Here's an example of a GET endpoint to fetch all users:
1// GET endpoint to fetch all users 2app.get('/users', async (req, res) => { 3 try { 4 const users = await User.find({}); 5 res.send(users); 6 } catch (error) { 7 res.status(500).send(error); 8 } 9}); 10
Update (PUT/PATCH): PUT or PATCH methods can be used for updating resources. PATCH is often preferred for partial updates. Here's an example of a PATCH endpoint to update a user:
1// PATCH endpoint to update a user 2app.patch('/users/:id', async (req, res) => { 3 try { 4 const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true }); 5 if (!user) { 6 return res.status(404).send(); 7 } 8 res.send(user); 9 } catch (error) { 10 res.status(400).send(error); 11 } 12}); 13
Delete (DELETE): The DELETE method is used to remove resources. Here's an example of a DELETE endpoint to delete a user:
1// DELETE endpoint to delete a user 2app.delete('/users/:id', async (req, res) => { 3 try { 4 const user = await User.findByIdAndDelete(req.params.id); 5 if (!user) { 6 return res.status(404).send(); 7 } 8 res.send(user); 9 } catch (error) { 10 res.status(500).send(error); 11 } 12}); 13
The above endpoints interact with the MongoDB database using Mongoose methods. When a client sends an HTTP request to an endpoint, the server processes the request, performs the necessary database operation, and then sends back a response.
To ensure these endpoints are accessible, we need to tell our Express server to use them. This is typically done by defining the routes in a separate file and then importing them into our main server file. For example, you might have a userRoutes.js file that looks like this:
1const express = require('express'); 2const User = require('./models/User'); 3const router = new express.Router(); 4 5// Define your endpoints here 6 7module.exports = router; 8
Then, in your main server file, you would use the routes like this:
1const userRouter = require('./userRoutes'); 2app.use(userRouter); 3
We've established the necessary backend functionality to interact with our data by connecting our REST API endpoints to the MongoDB database.
After setting up the back end and REST API endpoints, our focus shifts to the front end of our MERN stack application. React excels in building fast and interactive user interfaces. We'll start by setting up the entry point of our React application and then proceed to create components that will display and interact with the dynamic data from our MongoDB database.
The entry point of a React application is typically the index.js file located in the src folder. This is where we import the core React libraries and render our root React component to the DOM. Here's how to set up the entry point:
1import React from 'react'; 2import ReactDOM from 'react-dom'; 3import './index.css'; 4import App from './App'; // Importing the main App component 5 6ReactDOM.render( 7 <React.StrictMode> 8 <App /> 9 </React.StrictMode>, 10 document.getElementById('root') 11); 12
In this code snippet, we import React and ReactDOM. React is the library that allows us to define and manage our components, while ReactDOM provides the methods to interact with the DOM. We wrap our App component in React.StrictMode for catching potential problems in our application. The ReactDOM.render method then mounts our App component to the 'root' div in our index.html file.
React components are the building blocks of any React application. They allow us to split the UI into independent, reusable pieces that can be managed and tested individually. To display dynamic data, we'll create components that can interact with our back end to fetch, display, and update the data stored in MongoDB.
Here's an example of a simple UserList component that fetches and displays a list of users:
1import React, { useState, useEffect } from 'react'; 2import axios from 'axios'; // Importing axios to make HTTP requests 3 4const UserList = () => { 5 const [users, setUsers] = useState([]); // State to store our users 6 7 useEffect(() => { 8 const fetchUsers = async () => { 9 try { 10 const response = await axios.get('/users'); // Fetch users from our API 11 setUsers(response.data); // Update state with fetched users 12 } catch (error) { 13 console.error('Error fetching users:', error); 14 } 15 }; 16 17 fetchUsers(); 18 }, []); // The empty array ensures this effect runs once on component mount 19 20 return ( 21 <div> 22 <h2>User List</h2> 23 <ul> 24 {users.map(user => ( 25 <li key={user._id}>{user.name}</li> // Display each user's name 26 ))} 27 </ul> 28 </div> 29 ); 30}; 31 32export default UserList; 33
In this UserList component, we use the useState hook to create a state variable for storing the list of users and the useEffect hook to fetch the user data from our server when the component mounts. We use axios to make the HTTP GET request to our /users endpoint. The fetched data is then mapped and rendered as a list of user names.
This component can be imported and used in our App or any other component requiring a user list. As we build out our React application, we can create more components for different data models and functionalities, such as adding new users or editing existing ones.
We must connect the React front end and the Node.js back end to create a seamless application. This involves setting up the React client to send HTTP requests to the back-end server, which will handle these requests and interact with the MongoDB database accordingly.
Axios is a popular JavaScript library used to make HTTP requests from the browser. It's promise-based, which means it handles asynchronous operations well and integrates seamlessly with modern React code. In our React components, we can use Axios to send HTTP requests to our back-end server's API endpoints to perform CRUD operations. Here's a short example of using Axios to send a GET request:
1import axios from 'axios'; 2 3axios.get('/api/users') 4 .then(response => { 5 // Handle success 6 console.log(response.data); 7 }) 8 .catch(error => { 9 // Handle error 10 console.error('Error fetching data:', error); 11 });
React Router is a standard library for routing in React applications. It enables the navigation between different components in a single-page application by changing the URL without reloading the page. This provides a seamless user experience, like navigating through multiple pages on a traditional website.
To use React Router, you first need to install the react-router-dom package, which is designed for web applications:
1npm install react-router-dom 2
Once installed, you can set up React Router in your application by importing BrowserRouter from react-router-dom and wrapping your app's component hierarchy with it in your index.js file:
1import React from 'react'; 2import ReactDOM from 'react-dom'; 3import { BrowserRouter } from 'react-router-dom'; 4import App from './App'; 5 6ReactDOM.render( 7 <BrowserRouter> 8 <App /> 9 </BrowserRouter>, 10 document.getElementById('root') 11); 12
Within your React application, you can define different routes using the Route component from react-router-dom. Each Route maps a URL path to a React component, rendering that component when the URL matches the path.
Here's an example of how to define routes in your App component:
1import React from 'react'; 2import { Route, Switch } from 'react-router-dom'; 3import Home from './components/Home'; 4import About from './components/About'; 5import UserList from './components/UserList'; 6 7function App() { 8 return ( 9 <div> 10 <Switch> 11 <Route exact path="/" component={Home} /> 12 <Route path="/about" component={About} /> 13 <Route path="/users" component={UserList} /> 14 </Switch> 15 </div> 16 ); 17} 18 19export default App; 20
In this example, the Switch component renders the first Route that matches the current location's pathname. If the URL is /, the Home component is rendered; if it's /about, the About component is displayed; and if it's /users, the UserList component is shown. The exact prop ensures that the route for the Home component is only matched when the path is exactly /.
Cross-Origin Resource Sharing (CORS) is a security feature that restricts web browsers from requesting a domain different from the one that served the web page. This can be an issue when your React app and back-end server are hosted on other domains or ports.
To handle CORS in a Node.js server, you can use the cors middleware package:
1npm install cors 2
Then, include it in your server setup:
1const cors = require('cors'); 2const app = express(); 3 4app.use(cors()); // This will enable all CORS requests 5
Setting up CORS properly ensures your React app can communicate with your back-end server without any security issues related to cross-origin requests.
In summary, the synergy between MongoDB and React forms the heart of MERN stack development. MongoDB's flexible data handling complements React's dynamic user interfaces, enabling developers to build scalable and responsive web applications. By mastering these technologies, you can efficiently manage data and create compelling user experiences, setting the stage for successful full-stack development with the MERN stack.
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.