Server Setup With Express
Server Setup With Express
js
To begin our MERN stack tutorial, we’ll show you how to set up a server with Express.js and
Node.js.
To create a project folder, enter the folder through the terminal, then run the following
command:
$ npm init
Now it will ask you some questions about package name, version, entry point, etc. Hit enter if
you want to keep the default. After that, you will get something like this:
Select yes and you’re ready to go. It creates a file named package.json.
Installing dependencies
bcryptjs is a password hashing function designed by Niels Provos and David Mazières
body-parser allows us to get the data throughout the request
express is our main framework
mongoose is used to connect/interact with MongoDB
validation (as its name implies) is used for validation
Now I want to add nodemon as a dev dependency. If you don’t want to add this, you can skip it
— it’s optional.
$ npm i -D nodemon
nodemon is a utility that will monitor for any changes in your source and automatically restart
your server.
$ touch app.js
Then paste the code below:
// app.js
$ node app
You will see Server running on port 8082. You can also check it from the browser: open
the browser and enter http://localhost:8082.
At this point, if we change anything, we need to restart the server manually. But if we set up
nodemon, then we don’t have to restart it every time; nodemon will watch if there is any change
and restart the server automatically.
So what you need to do for that is a little change to the scripts in our package.json file. See
below:
// package.json
{
"name": "mern_a_to_z",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"start": "node app.js",
"app": "nodemon app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/nurislam03/MERN_A_to_Z.git"
},
"author": "Nur Islam",
"license": "MIT",
"bugs": {
"url": "https://github.com/nurislam03/MERN_A_to_Z/issues"
},
"homepage": "https://github.com/nurislam03/MERN_A_to_Z#readme",
"dependencies": {
"bcryptjs": "^2.4.3",
"body-parser": "^1.19.0",
"express": "^4.17.1",
"mongoose": "^5.5.15",
"validation": "0.0.1"
},
"devDependencies": {
"nodemon": "^1.19.1"
}
}
So, now you can run your project using this command:
$ npm install
$ npm run app
You will see the following changes in your terminal if everything goes right:
First, you need an account. Create one and follow the procedure. After creating an account, you
will see something like this:
Click on the Project 0 section (top left) and you will see a button for creating a new project.
Create a project and select the project.
Now, click on the Build a Cluster button from the project you have created. It will show you all
the information. At the bottom, you will see a section called Cluster Name, click on that and
enter a name for the database, then hit the Create Cluster button.
After two to three minutes, if everything goes well, you will find something like this:
Click on the CONNECT button and fill in the username and password form for your database.
Now hit the Create MongoDB User button. You can also choose either your current IP address
or a different IP address, it’s up to you.
Now you will get your database link, which we will use in our next step.
Our database is ready — now we need to add it to our project.
Inside the project folder, create another folder named config and inside it create two files
named default.json and db.js. Add the following code:
// default.json
{
"mongoURI":
"mongodb+srv://mern123:<password>@mernatoz-9kdpd.mongodb.net/test?
retryWrites=true&w=majority"
}
/* Replace <password> with your database password */
/* ------------------------------------------------------------------
*/
// db.js
console.log('MongoDB is Connected...');
} catch (err) {
console.error(err.message);
process.exit(1);
}
};
module.exports = connectDB;
NOTE: We need a little change in our app.js file to connect to the database. Update
your app.js with this:
// app.js
// Connect Database
connectDB();
$ npm i config
Now, you can run the project using the following command:
Great! So far we are on the right track. Our database is successfully connected. Now time to
complete the route setup, and after that, we will see how to create RESTful APIs.
Inside the api folder, create a file named books.js. We will create some APIs here to show
how it works in a moment.
// routes/api/books.js
module.exports = router;
Database model
In order to interact with our database, we need to create a model for each of our resources. So,
create a folder called models in the root, and inside the models folder, create a file
called Book.js and update it with this:
// models/Book.js
In this section, we’ll use React to build our user interfaces. React is a JavaScript library for
building user interfaces. It is maintained by Facebook and a community of individual developers
and other companies.
We’ll use Create React App to generate our initial file setup. CRA is a comfortable environment
for learning React and is the best way to start building applications in React. It offers a modern
build setup with no configuration.
We’ll also use webpack and Babel to bundle our modules and compile our JavaScript,
respectively. If you don’t know webpack or Babel well, no problem; you don’t need to install or
configure tools like webpack or Babel. They’re preconfigured and hidden so that you can focus
on the code. Just create a project, and you’re good to go.
You’ll also need any version of Node.js greater than 8.10 and any version of npm greater than
5.6 installed on your local development machine.
Before using any built-in command, we need to go inside the project folder.
$ cd mern_a_to_z_client
Now that we are in the project directory, we can use those available commands. If you’re using
Yarn:
$ yarn start
Or, if using npm:
$ npm start
To run the app in development mode, you can use any of the above commands, and you will see
the following message in your terminal.
Now open http://localhost:3000 to view it in the browser. This page will automatically
reload if you make changes to the code.
Initial project structure
Inside the project directory, our initial file structure should look like this:
We have got our initial setup file for the front-end part. Now we can start integrating our back
end with our front end. Before that, though, I want to add Bootstrap and Font Awesome’s CDN
to our project.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-
scale=1" />
<meta name="theme-color" content="#000000" />
<!--
manifest.json provides metadata used when your web app is
installed on a
user's mobile device or desktop. See
https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during
the build.
Only files inside the `public` folder can be referenced from the
HTML.
<title>MERN A to Z</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this
app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty
page.
</body>
</html>
Frontend tasks and features
We will work with five different features:
Axios is a lightweight HTTP client based similar to a Fetch API. Axios is a promise-based
async/await library for readable asynchronous code. We can easily integrate with React, and it is
effortless to use in any front-end framework.
Package.json file
// MERN_A_to_Z_Client - package.json
{
"name": "mern_a_to_z_client",
"version": "0.1.0",
"private": true,
"dependencies": {
"axios": "^0.19.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-router-dom": "^5.0.1",
"react-scripts": "3.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
1. CreateBook.js
2. ShowBookList.js
3. BookCard.js
4. ShowBookDetails.js
5. UpdateBookInfo.js
Setup route
.App {
text-align: center;
}
.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 40vmin;
pointer-events: none;
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.CreateBook {
background-color: #2c3e50;
min-height: 100vh;
color: white;
}
.ShowBookDetails {
background-color: #2c3e50;
min-height: 100vh;
color: white;
}
.UpdateBookInfo {
background-color: #2c3e50;
min-height: 100vh;
color: white;
}
.ShowBookList {
background-color: #2c3e50;
height: 100%;
width: 100%;
min-height: 100vh;
min-width: 100px;
color: white;
}
/* BookList Styles */
.list {
display: grid;
margin: 20px 0 50px 0;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 1fr;
grid-gap: 2em;
}
.card-container {
width: 250px;
border: 1px solid rgba(0,0,.125);
margin: 0 auto;
border-radius: 5px;
overflow: hidden;
}
.desc {
height: 130px;
padding: 10px;
}
.desc h2 {
font-size: 1em;
font-weight: 400;
}
.desc h3, p {
font-weight: 300;
}
.desc h3 {
color: #6c757d;
font-size: 1em;
padding: 10px 0 10px 0;
}
Adding our feature components
Now it’s time to add feature components to our MERN stack project.
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
onSubmit = e => {
e.preventDefault();
const data = {
title: this.state.title,
isbn: this.state.isbn,
author: this.state.author,
description: this.state.description,
published_date: this.state.published_date,
publisher: this.state.publisher
};
axios
.post('http://localhost:8082/api/books', data)
.then(res => {
this.setState({
title: '',
isbn:'',
author:'',
description:'',
published_date:'',
publisher:''
})
this.props.history.push('/');
})
.catch(err => {
console.log("Error in CreateBook!");
})
};
render() {
return (
<div className="CreateBook">
<div className="container">
<div className="row">
<div className="col-md-8 m-auto">
<br />
<Link to="/" className="btn btn-outline-warning float-
left">
Show BooK List
</Link>
</div>
<div className="col-md-8 m-auto">
<h1 className="display-4 text-center">Add Book</h1>
<p className="lead text-center">
Create new book
</p>
<div className='form-group'>
<input
type='text'
placeholder='ISBN'
name='isbn'
className='form-control'
value={this.state.isbn}
onChange={this.onChange}
/>
</div>
<div className='form-group'>
<input
type='text'
placeholder='Author'
name='author'
className='form-control'
value={this.state.author}
onChange={this.onChange}
/>
</div>
<div className='form-group'>
<input
type='text'
placeholder='Describe this book'
name='description'
className='form-control'
value={this.state.description}
onChange={this.onChange}
/>
</div>
<div className='form-group'>
<input
type='date'
placeholder='published_date'
name='published_date'
className='form-control'
value={this.state.published_date}
onChange={this.onChange}
/>
</div>
<div className='form-group'>
<input
type='text'
placeholder='Publisher of this Book'
name='publisher'
className='form-control'
value={this.state.publisher}
onChange={this.onChange}
/>
</div>
<input
type="submit"
className="btn btn-outline-warning btn-block mt-4"
/>
</form>
</div>
</div>
</div>
</div>
);
}
}
componentDidMount() {
axios
.get('http://localhost:8082/api/books')
.then(res => {
this.setState({
books: res.data
})
})
.catch(err =>{
console.log('Error from ShowBookList');
})
};
render() {
const books = this.state.books;
console.log("PrintBook: " + books);
let bookList;
if(!books) {
bookList = "there is no book record!";
} else {
bookList = books.map((book, k) =>
<BookCard book={book} key={k} />
);
}
return (
<div className="ShowBookList">
<div className="container">
<div className="row">
<div className="col-md-12">
<br />
<h2 className="display-4 text-center">Books List</h2>
</div>
<div className="col-md-11">
<Link to="/create-book" className="btn btn-outline-
warning float-right">
+ Add New Book
</Link>
<br />
<br />
<hr />
</div>
</div>
<div className="list">
{bookList}
</div>
</div>
</div>
);
}
}
return(
<div className="card-container">
<img src="https://commapress.co.uk/books/the-book-of-
cairo/cairo-provisional-v3/image%2Fspan3" alt="" />
<div className="desc">
<h2>
<Link to={`/show-book/${book._id}`}>
{ book.title }
</Link>
</h2>
<h3>{book.author}</h3>
<p>{book.description}</p>
</div>
</div>
)
};
The ShowBookDetails component has one task: it shows all the info we have about any book.
We have both delete and edit buttons here to get access.
componentDidMount() {
// console.log("Print id: " + this.props.match.params.id);
axios
.get
('http://localhost:8082/api/books/'+this.props.match.params.id)
.then(res => {
// console.log("Print-showBookDetails-API-response: " +
res.data);
this.setState({
book: res.data
})
})
.catch(err => {
console.log("Error from ShowBookDetails");
})
};
onDeleteClick (id) {
axios
.delete('http://localhost:8082/api/books/'+id)
.then(res => {
this.props.history.push("/");
})
.catch(err => {
console.log("Error form ShowBookDetails_deleteClick");
})
};
render() {
return (
<div className="ShowBookDetails">
<div className="container">
<div className="row">
<div className="col-md-10 m-auto">
<br /> <br />
<Link to="/" className="btn btn-outline-warning float-
left">
Show Book List
</Link>
</div>
<br />
<div className="col-md-8 m-auto">
<h1 className="display-4 text-center">Book's Record</h1>
<p className="lead text-center">
View Book's Info
</p>
<hr /> <br />
</div>
</div>
<div>
{ BookItem }
</div>
<div className="row">
<div className="col-md-6">
<button type="button" className="btn btn-outline-danger
btn-lg btn-block"
onClick={this.onDeleteClick.bind(this,book._id)}>Delete
Book</button><br />
</div>
<div className="col-md-6">
<Link to={`/edit-book/${book._id}`} className="btn btn-
outline-info btn-lg btn-block">
Edit Book
</Link>
<br />
</div>
</div>
{/* <br />
<button type="button" class="btn btn-outline-info btn-lg
btn-block">Edit Book</button>
<button type="button" class="btn btn-outline-danger btn-lg
btn-block">Delete Book</button> */}
</div>
</div>
);
}
}
UpdateBookInfo.js, as its name indicates, is responsible for updating a book’s info. An Edit
Book button will trigger this component to perform. After clicking Edit Book, we will see a
form with the old info, which we will be able to edit or replace.
componentDidMount() {
// console.log("Print id: " + this.props.match.params.id);
axios
.get
('http://localhost:8082/api/books/'+this.props.match.params.id)
.then(res => {
// this.setState({...this.state, book: res.data})
this.setState({
title: res.data.title,
isbn: res.data.isbn,
author: res.data.author,
description: res.data.description,
published_date: res.data.published_date,
publisher: res.data.publisher
})
})
.catch(err => {
console.log("Error from UpdateBookInfo");
})
};
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
onSubmit = e => {
e.preventDefault();
const data = {
title: this.state.title,
isbn: this.state.isbn,
author: this.state.author,
description: this.state.description,
published_date: this.state.published_date,
publisher: this.state.publisher
};
axios
.put
('http://localhost:8082/api/books/'+this.props.match.params.id, data)
.then(res => {
this.props.history.push('/show-
book/'+this.props.match.params.id);
})
.catch(err => {
console.log("Error in UpdateBookInfo!");
})
};
render() {
return (
<div className="UpdateBookInfo">
<div className="container">
<div className="row">
<div className="col-md-8 m-auto">
<br />
<Link to="/" className="btn btn-outline-warning float-
left">
Show BooK List
</Link>
</div>
<div className="col-md-8 m-auto">
<h1 className="display-4 text-center">Edit Book</h1>
<p className="lead text-center">
Update Book's Info
</p>
</div>
</div>
<div className='form-group'>
<label htmlFor="author">Author</label>
<input
type='text'
placeholder='Author'
name='author'
className='form-control'
value={this.state.author}
onChange={this.onChange}
/>
</div>
<div className='form-group'>
<label htmlFor="description">Description</label>
<input
type='text'
placeholder='Describe this book'
name='description'
className='form-control'
value={this.state.description}
onChange={this.onChange}
/>
</div>
<div className='form-group'>
<label htmlFor="published_date">Published Date</label>
<input
type='date'
placeholder='published_date'
name='published_date'
className='form-control'
value={this.state.published_date}
onChange={this.onChange}
/>
</div>
<div className='form-group'>
<label htmlFor="publisher">Publisher</label>
<input
type='text'
placeholder='Publisher of this Book'
name='publisher'
className='form-control'
value={this.state.publisher}
onChange={this.onChange}
/>
</div>
</div>
</div>
);
}
}
If we try to call our back-end API from the front-end part, it gets an error that says: “Access to
XMLHttpRequest at ‘http://localhost:8082/api/books’ from origin
‘http://localhost:3000’ has been blocked by CORS policy: Response to preflight request
doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the
requested resource.”
To solve this, we need to install cors in our back-end (server-side) project. Go to the project
folder (e.g., MERN_A_to_Z) and run:
// routes
const books = require('./routes/api/books');
// Connect Database
connectDB();
// cors
app.use(cors({ origin: true, credentials: true }));
// Init Middleware
app.use(express.json({ extended: false }));
// use Routes
app.use('/api/books', books);
$ npm install
$ npm run app
$ npm install
$ npm start
Testing our MERN stack app in the browser
Let’s check everything in the browser. Open http://localhost:3000 in your browser. Now you can
add a book, delete a book, show the list of books, and edit books. The following routes should
perform accordingly:
The LogRocket Redux middleware package adds an extra layer of visibility into your user
sessions. LogRocket logs all actions and state from your Redux stores.
Modernize how you debug your React apps — start monitoring for free.
Share this:
#full stack
#node
#react
Cristian Rita
May 26, 2022 5 min read
İrem Karaoğlu
May 26, 2022 4 min read
1. Felix Olola Says:
2. Alim Bolar Says:
Hi.. Any idea when the next part would be available?.. I’ve started this without realising
that this was only one part.. ;-).. so either I wait for our second part or look for another
tutorial.. please advise..
3. Nur_islam Says:
4. Nur_islam Says:
thanks for following this tutorial. you have to wait 2-3 weeks for the 2nd part.
Thanks… Really good article for me and of course helping me in my study about
mongodb. I can’t wait for the following article.
5. Farouk BF Says:
6. Mssadewa Says:
app.use('/api', routes);
7. Dmitry H. Says:
8. Jamal Says:
although i have my IP whitlisted and even switched to accepting request from any IP but
still getting this error
9. JOB Says:
11. AV Says:
I like the content, but why did you install bcryptjs? I don’t see it being used in your app.
I’m using this in the class I teach and it’s extremely helpful. Great work!
13. Avantika Says:
This post gives a detailed outline of the MERN Stack. Thanks for sharing.
14. MichaelRydl Says:
at Object. (/mnt/c/Users/Michael/Desktop/WebApps/mern_stack/app.js:7:1)
at Module._compile (internal/modules/cjs/loader.js:955:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:991:10)
at Module.load (internal/modules/cjs/loader.js:811:32)
at Function.Module._load (internal/modules/cjs/loader.js:723:14)
at Function.Module.runMain (internal/modules/cjs/loader.js:1043:10)
at internal/main/run_main_module.js:17:11
[nodemon] app crashed – waiting for file changes before starting…
[nodemon] restarting due to changes…
[nodemon] starting `node app.js`
/mnt/c/Users/Michael/Desktop/WebApps/mern_stack/app.js:7
connectDB();
^
1. Mike Says:
I believe the issue may be that you don’t have ‘module.exports = connectDB;’ at the
bottom of the file. So app.js is not actually importing the specific connectDB
function you wrote.
15. Mike Says:
There’s a bug in the db.js instructions. The word “parser” should be capitalized in:
useNewUrlparser: true
16. Mike Says:
April 14, 2020 at 12:24 am
This is a great tutorial! Got one more issue: With just the code in Part 1, it’s not possible to
use Postman to test the APIs. To make it work, app.js needs to be updated to include:
17. Aumkar Says:
Can someone help me? I’m getting the same error as @MichaelRydl, where I am able to
connect to the DB. I replaced the url in the default.json with the url on the ATLAS, with the
username and password that I set for the user, however am still facing this error.
18. Mike Says:
I believe the issue may be that you don’t have ‘module.exports = connectDB;’ at the bottom
of the file. So app.js is not actually importing the specific connectDB function you wrote.
// parse application/json
app.use(bodyParser.json())
21. Khushboo Jain Says:
You really did hard research and wrote very well. I will try to always keep in mind these
points. Great job
We should not use the ‘_id’ property created by mongodb since it is a security risk. Refer
to: https://stackoverflow.com/questions/44994863/is-it-a-good-idea-to-use-the-id-value-of-
a-mongodb-object-in-the-dom
24. Lio Says:
If you encounter the following error/warning when running the react app:
“Warning: Functions are not valid as a React child.This may happen if you return a
Component instead of from render.”
Can someone help? Great tutorial, but for some reason when I update the app.js file with the
recommended code, my database crashes when I try to run it with the following console
message. The db runs without any errors before this step. Any suggestions?
26. Sarah Says:
Hey there! What if my package.json is missing a couple of the dependencies listed in this
project? I went through everything step by step but it seems your package.json has a lot
more scripts and dependencies than mine…
27. Sarah Says:
March 21, 2022 at 6:55 pm
Has anyone tried using functional components and hooks? My apps front end wont work
because I’m not using functional components
Leave a Reply
Yeah
No
compare notes
Are you up to speed on all of this new CSS stuff? Chris Coyier and Kaelan compare notes on
CSS and frontend development (they also discuss MDN plus).
LISTEN NOW
PODROCKET|EP. 26 Redux is alive and well with Mark Erikson
What is modern Redux? What is it with the obsession of declaring Redux dead? In this episode,
Ben and Brian interview Mark Erikson to talk about all things Redux.
LISTEN NOW
PODROCKET|EP. 29 Continuing education with Eve Porcello
In this episode, we talk to Eve Porcello about her experience teaching web development and
Moon Highway, a training and curriculum development company she runs.
LISTEN NOW
Rome and Rome Tools, Inc. with Sebastian
PODROCKET|EP. 34
compare notes
Are you up to speed on all of this new CSS stuff? Chris Coyier and Kaelan compare notes on
CSS and frontend development (they also discuss MDN plus).
LISTEN NOW
PreviousNext