DEV Community

Cover image for Build an E-Commerce Website with MERN Stack - Part 3 (Authentication and Items)
Kumar Shubham
Kumar Shubham

Posted on • Updated on • Originally published at shubhamstudent5.Medium

Build an E-Commerce Website with MERN Stack - Part 3 (Authentication and Items)

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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));
}
Enter fullscreen mode Exit fullscreen mode

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});
    });
}
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
lcprog profile image
LC

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....

Collapse
 
shubham1710 profile image
Kumar Shubham

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.