Hello friends! So, this is the third part of the MERN Stack series we have recently started. In the first part, we all learnt how to set up the project and had explanations about various things we are going to use in the project and we developed all our models for the project in the second part with the help of Mongoose and MongoDB.
Notice: I will publish the complete detailed version of all the articles on the Medium website. Here I will give an overview and give the codes for the various pages part by part. It would be a 6-7 part series.
So, please click here to go to Medium and read it in completion. (These are friend links so do not worry about paywall)
Now, in the third part, we will build the backend part which would handle the authentication and items in our web application by building out the APIs with the help of Express Router and we will also be defining a custom middleware function to check whether a user is authenticated or not.
To keep things clean and simple, we would create a new folder named routes in our root folder. This folder would contain all the routes we need for this project.
We will also create a folder named controllers in which we would put all the function we would be calling once we hit an API endpoint. So, we would separate the function in a different folder and import them in routes folder to use them.
Inside the routes folder, we would create four files — auth, item, cart and order. These four files would contain the routes relevant to the authentication, items, cart and orders respectively.
Similarly, we would create four files inside the controllers' folder, one each for each file of routes folder. Those would be — authControllers, itemControllers, cartControllers and orderControllers respectively.
So, we would now start building our Routes folder which would be simple since we will put all the logic in the controllers' folder and not directly in the routes folder.
Routes
Auth Routes
const { Router } = require('express');
const authController = require('../controllers/authControllers');
const router = Router();
const auth = require('../middleware/auth');
router.post('/register', authController.signup);
router.post('/login', authController.login);
router.get('/user', auth, authController.get_user);
module.exports = router;
Item Routes
const { Router } = require('express');
const itemController = require('../controllers/itemControllers');
const router = Router();
router.get('/items', itemController.get_items);
router.post('/items',itemController.post_item);
router.put('/items/:id',itemController.update_item);
router.delete('/items/:id',itemController.delete_item);
module.exports = router;
Controllers
Auth Controller
const User = require('../models/User');
const jwt = require('jsonwebtoken');
const config = require('config');
const bcrypt = require('bcrypt');
module.exports.signup = (req,res) => {
const { name, email, password } = req.body;
if(!name || !email || !password){
res.status(400).json({msg: 'Please enter all fields'});
}
User.findOne({email})
.then(user => {
if(user) return res.status(400).json({msg: 'User already exists'});
const newUser = new User({ name, email, password });
// Create salt and hash
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(password, salt, (err, hash) => {
if(err) throw err;
newUser.password = hash;
newUser.save()
.then(user => {
jwt.sign(
{ id: user._id },
config.get('jwtsecret'),
{ expiresIn: 3600 },
(err, token) => {
if(err) throw err;
res.json({
token,
user: {
id: user._id,
name: user.name,
email: user.email
}
});
}
)
});
})
})
})
}
module.exports.login = async (req,res) => {
const { email, password } = req.body;
if(!email || !password){
res.status(400).json({msg: 'Please enter all fields'});
}
User.findOne({email})
.then(user => {
if(!user) return res.status(400).json({msg: 'User does not exist'});
// Validate password
bcrypt.compare(password, user.password)
.then(isMatch => {
if(!isMatch) return res.status(400).json({ msg: 'Invalid credentials'});
jwt.sign(
{ id: user._id },
config.get('jwtsecret'),
{ expiresIn: 3600 },
(err, token) => {
if(err) throw err;
res.json({
token,
user: {
id: user._id,
name: user.name,
email: user.email
}
});
}
)
})
})
}
module.exports.get_user = (req,res) => {
User.findById(req.user.id)
.select('-password')
.then(user => res.json(user));
}
Item Controller
const Item = require('../models/Item');
module.exports.get_items = (req,res) => {
Item.find().sort({date:-1}).then(items => res.json(items));
}
module.exports.post_item = (req,res) => {
const newItem = new Item(req.body);
newItem.save().then(item => res.json(item));
}
module.exports.update_item = (req,res) => {
Item.findByIdAndUpdate({_id: req.params.id},req.body).then(function(item){
Item.findOne({_id: req.params.id}).then(function(item){
res.json(item);
});
});
}
module.exports.delete_item = (req,res) => {
Item.findByIdAndDelete({_id: req.params.id}).then(function(item){
res.json({success: true});
});
}
Auth Middleware function
const config = require('config');
const jwt = require('jsonwebtoken');
function auth(req, res, next) {
const token = req.header('x-auth-token');
// Check for token
if(!token){
return res.status(401).json({ msg: 'No token, authorization denied'});
}
try{
// Verify token
const decoded = jwt.verify(token, config.get('jwtsecret'));
//Add user from payload
req.user = decoded;
next();
} catch(e){
res.status(400).json({ msg:'Token is not valid'});
}
}
module.exports = auth;
So, that was all about the middleware function. We have now covered everything we wanted to cover in the third part. In the fourth part, we will deal with the routes and controllers of Cart and the Order. We will handle the payments using Stripe Checkout in the next part of the series.
Thank you, everyone, for reading this. Hope you gained some real knowledge and learnt something new today.
To read the complete tutorial, please move to Medium and read the complete article.
Top comments (2)
this would have been such a great tutorial article, but unfortunately you fell prey almost every other tutorial where you present only a portion of the material and then forget the rest. where the hell is the client portion.
this article should have been titled "how to create a node express back-end" or better yet, you should have had your coffee and then skipped the exercise altogether, you would have done us a great favor by not enticing us with something you were not going to complete.
where are the mongo urls samples, where are the config samples, and where is the client code
what a shame....
I have not forgotten the rest. I will complete each and every part including the client portion and config file. It is planned to be a 6-7 part series. I have only published 3 parts till now. More parts will come in coming days. It would be complete.
So, please wait for the parts to come. I hope you enjoy the articles.