How to build CRUD REST API in nodejs with MongoDB and express js
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.
For 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.
- Express: Express js is an node js popular framework. Express js provides set routing, validations and interceptor for building the REST API.
- 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.
- 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
- 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
- Bcrypt: Bycrypt is especially helps to hash the passwords
- Body-parser:
- 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.