Learn Simpli

Free Online Tutorial For Programmers, Contains a Solution For Question in Programming. Quizzes and Practice / Company / Test interview Questions.

How to build CRUD REST API in node js with MongoDB and Express js

In this chapter, you will learn how to build CRUD REST API in node js with MongoDB and express js. We are starting from the beginning to the end with step by steps to how to build CRUD REST API in node js with MongoDB and express js.

How to build CRUD REST API in nodejs with MongoDB and express jsFor load balancing application that serves millions of visitor request in a day may need REST API in node js.

We are using the below packages to How to build CRUD REST API in node js with MongoDB and express js.

  1. Express: Express js is an node js popular framework. Express js provides set routing, validations and interceptor for building the REST API.
  2. Mongoose: Mongoose is similar to ORM in any other framework like .net or Laravel. So mongoose is object data modeling that provides set of futures for validating the data types.
  3. JWT: JSON Web Token JWT provides set of functions to create the tokens that can be shared between the client parties. Token can be used as identity and its signed copy of JWT. JWT token is very secure
  4. Node-input-validator: Input validator is a node js library which helps to validate the data types. Especially it is very helpful in REST API to validate the incomming data that is been submitted by the POST, GET, PUT and DELETE
  5. Bcrypt: Bycrypt is especially helps to hash the passwords
  6. Body-parser:
  7. Express-validator:

How to build rest API in node js?
Now let’s start building the REST API with step by step. Make sure you have node js and MongoDB in your system.

Step 1:
Create a directory nodejs-rest-api-with-jwt
Open the visual code editor add the nodejs-rest-api-with-jwt directory into working space
Open the terminal run the command: npm init
Create the directory structure

config
controllers
library
models
routes
services

Step 2:
Create the file config/global.config.js and paste the below code

module.exports = {
    "controllerPath":"controllers",
    "modelPath":"models",
    "servicePath":"services",
    "libraryPath":"library",
    "routePath":"routes",
    "dbPath":"config",
    "port": 3000,
    "appEndpoint": "http://localhost:3000",
    "apiEndpoint": "http://localhost:3000",
    "jwtSecret": "FGHJK",
    "jwtExpirationInSeconds": 36000,
    "environment": "dev",
    "development": true
};

Create the file config/mongodb.config.js and paste the below code

// Mongoose and MongoDB setup
const mongoose = require('mongoose');
const mongoDB = 'mongodb://localhost:27017/api2';
mongoose.connect(mongoDB, {
    useNewUrlParser: true,
    useUnifiedTopology: true
});
mongoose.Promise = global.Promise;
module.exports = mongoose;

Create the file controllers/user/user.controller.js and paste the below code

const config = require('../../config/global.config');
const userService = require(`../../${config.servicePath}/user/user.service`);
const
{
    normalizeErrors
} = require(`../../${config.libraryPath}/mongoose.library`);
const jwt = require('jsonwebtoken');
const
{
    Validator
} = require('node-input-validator');
const apiLibray = require(`../../${config.libraryPath}/api.library`);


exports.register = async function(req, res)
{
    try
    {
        let inputValidator = new Validator(req.body,
        {
            name: 'required|maxLength:150|minLength:3|regex:[A-Za-z0-9]',
            phoneNumber: 'required|phoneNumber|maxLength:13|minLength:10',
            email: 'required|email',
            password: 'required|same:confirmPassword',
            confirmPassword: 'required',
        });

        inputValidator.check().then((matched) =>
        {
            // res.status(200).send(matched);

            if (!matched)
            {
                let inputErrors = inputValidator.errors;
                let clientResponse = apiLibray.responseFailure(false, 422, 'Validation failed...', inputErrors);
                return res.json(
                    clientResponse
                );
            }
        });
        let requestRegistration = userService.register(req.body);
        requestRegistration.then(function(result)
            {

                console.log('Promise resolve has been received...');
                let clientResponse = apiLibray.responseSuccess(true, 200, 'User has been created...');
                return res.json(
                    clientResponse
                );

            },
            function(err)
            {

                console.log('Promise reject has been received...');
                console.log(JSON.stringify(err));
                if (err.responseCode == 201)
                {
                    let clientResponse = apiLibray.responseFailure(false, 422, 'Validation failed...', err.data);
                    return res.json(
                        clientResponse
                    );
                }
                else if (err.responseCode == 202)
                {
                    let clientResponse = apiLibray.responseFailure(false, 422, `User with ${req.body.email} already exist...`);
                    return res.json(
                        clientResponse
                    );
                }
            });

        //   await userService.register(req.body).then(function(data) {
        //       let clientResponse=apiLibray.responseSuccess(true,200,'User has been created...');
        //         return res.json(
        //             clientResponse
        //         );
        //   });
    }
    catch (e)
    {
        console.log(e);
    }


}
exports.login=async function(req,res)
{
    try
    {
        let loginValidator = new Validator(req.body,
        {
            email: 'required|email',
            password: 'required|minLength:3'
        });

        loginValidator.check().then((matched) =>
        {
            // res.status(200).send(matched);

            if (!matched)
            {
                let inputErrors = loginValidator.errors;
                let clientResponse = apiLibray.responseFailure(false, 422, 'Validation failed...', inputErrors);
                return res.json(
                    clientResponse
                );
            }
        });
        let requestLogin = userService.login(req.body);
        requestLogin.then(function(result)
            {

                console.log('Promise resolve has been received...');
                let clientResponse = apiLibray.responseSuccess(true, 200, 'User has been authenticated...',{"token":result.data});
                return res.json(
                    clientResponse
                );

            },
            function(err)
            {

                console.log('Promise reject has been received...');
                console.log(JSON.stringify(err));
                if (err.responseCode == 201)
                {
                    let clientResponse = apiLibray.responseFailure(false, 422, 'Validation failed...', err.data);
                    return res.json(
                        clientResponse
                    );
                }
                else if (err.responseCode == 202)
                {
                    let clientResponse = apiLibray.responseFailure(false, 422, `Wrong email or password combination...`);
                    return res.json(
                        clientResponse
                    );
                }
            });

        //   await userService.register(req.body).then(function(data) {
        //       let clientResponse=apiLibray.responseSuccess(true,200,'User has been created...');
        //         return res.json(
        //             clientResponse
        //         );
        //   });
    }
    catch (e)
    {
        console.log(e);
    }
}
exports.getUser = function(req, res)
{
    const requestedUserId = req.params.id;
    const user = res.locals.user;

    if (requestedUserId === user.id)
    {
        User.findById(requestedUserId, function(err, foundUser)
        {
            if (err)
            {
                return res.status(422).send(
                {
                    errors: normalizeErrors(err.errors)
                });
            }

            return res.json(foundUser);
        })

    }
    else
    {
        User.findById(requestedUserId)
            .select('-revenue -stripeCustomerId -password')
            .exec(function(err, foundUser)
            {
                if (err)
                {
                    return res.status(422).send(
                    {
                        errors: normalizeErrors(err.errors)
                    });
                }

                return res.json(foundUser);
            })
    }
}


exports.authMiddleware = function(req, res, next)
{
    const token = req.headers.authorization;

    if (token)
    {
        const user = parseToken(token);

        User.findById(user.userId, function(err, user)
        {
            if (err)
            {
                return res.status(422).send(
                {
                    errors: normalizeErrors(err.errors)
                });
            }

            if (user)
            {
                res.locals.user = user;
                next();
            }
            else
            {
                return notAuthorized(res);
            }
        })
    }
    else
    {
        return notAuthorized(res);
    }
}

function parseToken(token)
{
    return jwt.verify(token.split(' ')[1], config.jwtSecret);
}

function notAuthorized(res)
{
    return res.status(401).send(
    {
        errors: [
        {
            title: 'Not authorized!',
            detail: 'You need to login to get access!'
        }]
    });
}

Create the file library/api.library.js and paste the below code

const jwt = require('jsonwebtoken');
const userModel = require('../models/user/user.model');
const config = require('../config/global.config');
module.exports = {
    responseSuccess: function(success=null,code=null,message=null,data=null) {
        
        let responseObject={
            success:success,
            responseCode:code,
            message:message,
            data:data
        }
        return responseObject;
    },
    responseFailure: function(success=null,errorCode=null,errorMessage=null,errorData=null) {
        
        let responseObject={
            success:success,
            responseCode:errorCode,
            message:errorMessage,
            errors:errorData
        }
        return responseObject;
    },
    validateJwtToken: function(req, res, next)
    {
        const token = req.headers.authorization;

    if (token) {
        const user = parseToken(token);

        userModel.findById(user.userId, function(err, user) {
            if (err) {
                return res.status(422).send({
                    errors: normalizeErrors(err.errors)
                });
            }

            if (user) {
                res.locals.user = user;
                next();
            } else {
                return notAuthorized(res);
            }
        })
    } else {
        return notAuthorized(res);
    }
    }
}

function parseToken(token) {
    return jwt.verify(token.split(' ')[1], config.jwtSecret);
}

function notAuthorized(res) {
    return res.status(401).send({
        errors: [{
            title: 'Not authorized!',
            detail: 'You need to login to get access!',
            redirectUrl:'/login'
        }]
    });
}

Create the file library/auth.library.js and paste the below code

const jwt = require('jsonwebtoken'),
config = require('./env.config');
module.exports.isAuthorized  = function(req, res, next) {

    jwt.verify(req.headers['x-access-token'], req.app.get(config.jwtSecret), function(err, decoded) {
        if (err) {
            res.json({
                status: "error",
                message: err.message,
                data: null
            });
        } else {
            // add user id to request
            req.body.userId = decoded.id;
            next();
        }
    });
}

Create the file library/mongoose.library.js and paste the below code

module.exports = {
  normalizeErrors: function(errors) {
    let normalizeErrors = [];

    for (let property in errors) {
      if (errors.hasOwnProperty(property)) {
        normalizeErrors.push({title: property, detail: errors[property].message});
      }
    }

    return normalizeErrors;
  }
}

Create the file routes/user.route.js and paste the below code

const express = require('express');
const router = express.Router();
const userController = require('../controllers/user/user.controller');
router.post('/register', userController.register);
router.post('/login', userController.login);
module.exports = router;

Create the file user/user.service.js and paste the below code

const userModel = require('../../models/user/user.model');
const config = require('../../config/global.config');
const
{
    normalizeErrors
} = require(`../../library/mongoose.library`);

const jwt = require('jsonwebtoken');

exports.register = async function(userData)
{
    return new Promise(function(resolve, reject)
    {
        let name = userData.name;
        let phoneNumber=userData.phoneNumber;
        let email = userData.email;
        let password = userData.password;

        userModel.findOne(
        {
            email
        }, function(err, existingUser)
        {
            console.log(''+JSON.stringify(err));
            console.log(JSON.stringify(existingUser));
            if (err)
            {

                let errors = normalizeErrors(err.errors);
                let response = {
                    responseCode: 201,
                    success: false,
                    data: errors
                };
                // console.log(response);
                reject(response);
            }

            if (existingUser)
            {
                let response = {
                    responseCode: 202,
                    success: false,
                    data: 'User already exists...'
                };
                // console.log(response);
                reject(response);
            }

            const user = new userModel(
            {
                name,
                phoneNumber,
                email,
                password
            });

            user.save(function(err)
            {
                console.log("Trying to create...");
                if (err)
                {
                    let errors = normalizeErrors(err.errors);
                    let response = {
                        responseCode: 201,
                        success: false,
                        data: errors
                    };
                    // console.log(response);
                    reject(response);
                }
                else
                {
                    let response = {
                        responseCode: 200,
                        success: true,
                        data: "User has been created"
                    };
                    // console.log(response);
                    resolve(response);
                }

            })
        })
    });
};

exports.login = async function(userData)
{
    return new Promise(function(resolve, reject)
    {
        let email = userData.email;
        let password = userData.password;
        if (!email && !password)
        {
            let response = {
                responseCode: 201,
                success: false,
                data: "Email and Password is required..."
            };
            // console.log(response);
            reject(response);
        }
        userModel.findOne(
        {
            email
        }, function(err, user)
        {
            if (err)
            {
                let errors = normalizeErrors(err.errors);
                let response = {
                    responseCode: 201,
                    success: false,
                    data: errors
                };
                // console.log(response);
                reject(response);

            }

            if (!user)
            {

                let response = {
                    responseCode: 202,
                    success: false,
                    data: "User does not exist..."
                };
                // console.log(response);
                reject(response);
            }
            if (user != null)
            {
                if (user.hasSamePassword(password))
                {
                    const token = jwt.sign(
                    {
                        userId: user.id,
                        name: user.name
                    }, config.jwtSecret,
                    {
                        expiresIn: '1h'
                    });

                    let response = {
                        responseCode: 200,
                        success: true,
                        data: token
                    };
                    // console.log(response);
                    resolve(response);
                }
                else
                {
                    let response = {
                        responseCode: 201,
                        success: false,
                        data: "Wrong email or password..."
                    };
                    // console.log(response);
                    reject(response);
                }
            }



        });
    });
};

Create .babelrc in the root directory and paste the below code

{ 
    "presets": ["@babel/preset-env"] 
}

Create index.js in route directory and paste below code

// common files
const config = require('./config/global.config');
const apiLibray = require(`./${config.libraryPath}/api.library`),
    express = require('express'),
    logger = require('morgan'),
    movieRoutes = require(`./${config.routePath}/movie.route`),
    userRoutes = require(`./${config.routePath}/user.route`),
    bodyParser = require('body-parser'),
    mongoose = require(`./${config.dbPath}/mongodb.config`),
    app = express();

// connection to mongodb
mongoose.connection.on('error', console.error.bind(console, 'Could not connect to the MongoDB...'));
mongoose.set('useCreateIndex', true);

// Log if development mode is true
if (config.development == true) {
    app.use(logger('dev'));
}
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: false
}));

// API base
var APIPath = '/api/v/1';
// Routing for users model
app.use(APIPath+'/user', userRoutes);

// Routing for movies model
app.use(APIPath+'/movie', apiLibray.validateJwtToken, movieRoutes);


app.get('/', function(req, res) {
    let clientResponse=apiLibray.responseSuccess(true,200,'Welcome to REST API design tutorial...');
    res.json(
        clientResponse
    );
});

// handle 404 error
app.use(function(req, res, next) {
    let err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// handle errors
app.use(function(err, req, res, next) {
    console.log(err);
    if (err.status === 404)
    {
        let clientResponse=apiLibray.responseSuccess(false,500,'Something is not working...');
        res.json(
            clientResponse
        );
    }
    else
    {
        let clientResponse=apiLibray.responseSuccess(false,500,'Something is not working...');
        res.json(
            clientResponse
        );
    }
        
});

app.listen(config.port, function() {
    console.log(`Node server listening on port ${config.port}`);
});

Paste the below code in package.json

{
  "name": "nodejs-rest-api-with-jwt",
  "version": "1.0.0",
  "description": "api",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "bcrypt": "^3.0.6",
    "body-parser": "^1.19.0",
    "express": "^4.17.1",
    "express-validator": "^6.2.0",
    "jsonwebtoken": "^8.5.1",
    "mongoose": "^5.7.5",
    "morgan": "^1.9.1",
    "node-input-validator": "^4.1.0"
  },
  "devDependencies": {
    "@babel/core": "^7.6.4",
    "@babel/preset-env": "^7.6.3"
  }
}

Step 3:
Run the command: npm install
Run the command: node index

Now you should see the output in console Node server listening on port 3000
Goto the postman and hit the url:

Now to register user got to : http://localhost:3000/api/v/1/user/register

Method: POST
and put the below payload:

{
  "name":"Stark",
  "email":"stark@john.com",
  "phoneNumber":"9898989898",
  "password":"123",
  "confirmPassword":"123"
}

You should receive the response:

{
    "success": true,
    "responseCode": 200,
    "message": "User has been created...",
    "data": null
}

Now go to login: http://localhost:3000/api/v/1/user/login
Method: POST
and put the below payload:

{
  "email":"stark@john.com",
  "password":"123"
}

You should receive the response

{
    "success": true,
    "responseCode": 200,
    "message": "User has been authenticated...",
    "data": {
        "token": "ey-encrypted-token"
    }
}

 

 

One thought on “How to build CRUD REST API in nodejs with MongoDB and express js

Comments are closed.