Setup NodeJS Environment

npm init

npm install <Install the packages required e.g express, nodemon, etc>

Common packages that are required for any standard application:

1)express

2)http

3)body-parser

Configure NodeJS Development Environment to restart automatically upon change

1)Open package.json

2)Insert below code in the “scripts” section:

    “start”: “nodemon app.js”

3)Execute “npm start”

This will start your app.js through nodemon, which will restart the process in case any update is made to any file in the project.

Creating a Server using NodeJS

const http = require('http')
const app = http.createServer()
app.listen(3000, () => { 
console.log('NodeJS started listening on port 3000')
})

How to import NodeJS Modules

const http = require('http')
const https = require('https')

Built in NodeJS modules

ModuleDescription
assertProvides a set of assertion tests
bufferTo handle binary data
child_processTo run a child process
clusterTo split a single Node process into multiple processes
cryptoTo handle OpenSSL cryptographic functions
dgramProvides implementation of UDP datagram sockets
dnsTo do DNS lookups and name resolution functions
domainDeprecated. To handle unhandled errors
eventsTo handle events
fsTo handle the file system
httpTo make Node.js act as an HTTP server
httpsTo make Node.js act as an HTTPS server.
netTo create servers and clients
osProvides information about the operation system
pathTo handle file paths
punycodeDeprecated. A character encoding scheme
querystringTo handle URL query strings
readlineTo handle readable streams one line at the time
streamTo handle streaming data
string_decoderTo decode buffer objects into strings
timersTo execute a function after a given number of milliseconds
tlsTo implement TLS and SSL protocols
ttyProvides classes used by a text terminal
urlTo parse URL strings
utilTo access utility functions
v8To access information about V8 (the JavaScript engine)
vmTo compile JavaScript code in a virtual machine
zlibTo compress or decompress files
Source – https://www.w3schools.com/nodejs/ref_modules.asp

Using the express module

const express = require('express')
app = new express()
app.listen(3000, () => {
console.log('NodeJS started listening on port 3000')
})

How to read GET request parameters?

const http = require('http')

const express = require('express')
app = new express()
app.listen(3000, () => {
console.log('NodeJS started listening on port 3000')
})

const bodyparser = require('body-parser')
app.use(bodyparser.urlencoded({extended: true})) //This step is to accept x-www-form-urlencoded //data which is nothing but the data sent from HTML forms
app.use(bodyparser.json()); //This step is required to accept JSON request from JavaScript fetch or using axis module. You need either one of the above 2 lines depending on the use case.
app.get('/admin', (req, res) => {
console.log('request parameters = '+req.query.name)
res.end('Hello '+req.query.name)
})

Note that the "name" in req.query.name should exactly match the name of the parameter provide in HTML Form.

How to read POST request body?

const express = require('express')
app = new express()
app.listen(3000, () => {
console.log('NodeJS started listening on port 3000')
})

const bodyparser = require('body-parser')
app.use(bodyparser.urlencoded({extended: true})) //This step is to accept x-www-form-urlencoded //data which is nothing but the data sent from HTML forms

app.post('/registerUser', (req, res) => {
res.end('Hello '+req.body.name)//name is a form field that    //should be passed by the user
})

Comparison among req.params, req.query and req.body

Suppose you are fetching a request using React’s axios module as below.

      axios('http://localhost:4000/admin/adminPost/xdsdfwe3423432hjgh2b34b2?name=Animesh&job=self', {
        method: "POST",
        data: {
          name: 'animesh@gmail.com'
        }
      })
      .then(res => {
        console.log("response received ...");
      })

Below is how your backend NodeJS code looks like:

req.post('/admin/adminPost/:postID', (req, res, next) => {
    console.log("Request Params = ",req.params.postID);
    console.log("Request Query = ",req.query);
    console.log("Request Body = ",req.body.name);
}, adminPost)

Below is the Output:

Request Params = xdsdfwe3423432hjgh2b34b2
Request Query = { name: ‘Animesh’, job: ‘self’ }
Request Body = animesh@gmail.com

Enable static path for the NodeJS project/app

Just use the below middleware to define the static path. This will enable access to any files under images or under any subdirectories under images without further definition of routes.

app.use('/images', express.static(path.join(__dirname,'images')))

Difference between module.exports and exports

module.exports can be used to export only one value from a file. It may be a string, and object or a function. If you have multiple module.exports in a file, only the last one will be exported.

On the other hand, exports can be used to export multiple objects, functions or strings from a JS file.

Below example demonstrates these 2 use cases, with the output.

NODEJS CODE
app.js
//module.exports can be used to export only one value. It may be a string, and object or a function. If you have multiple module.exports in a file, only the last one will be exported.
console.log("********************* OUTPUT FROM module.exports *********************");
const stdName = require('./external/single')
console.log("Name of the Student = "+stdName);
console.log("**********************************************************************\n");

//exports can be used to export multiple items (objects, functions, strings etc. from the same js file)
console.log("********************* OUTPUT FROM exports *********************");
const student = require('./external/multiple')
console.log("Student1 = "+student.stdName1);
console.log("Student2 = "+student.stdName2);
console.log("Student3 = "+student.stdName3);
console.log("Student4 = "+student.stdName4);
console.log("getStudentClass function = "+student.getStdClass);
console.log("***************************************************************");

single.js
const studentName = "Animesh Banerjee"
module.exports = studentName

multiple.js
exports.stdName1 = "Animesh"
exports.stdName2 = "Aishani"
exports.stdName3 = "Sudipto"
exports.stdName4 = "Moumita"
exports.getStdClass = () => {
    console.log("This is the getStdClass function provided by multiple.js");
}

***********************************************************************************************

OUTPUT
 OUTPUT FROM module.exports 
 Name of the Student = Animesh Banerjee
 
 OUTPUT FROM exports 
 Student1 = Animesh
 Student2 = Aishani
 Student3 = Sudipto
 Student4 = Moumita
 getStudentClass function = () => {
     console.log("This is the getStdClass function provided by multiple.js");
 }
 

Implementing the Router to segregate the requests

In MVC architecture, we have the views, controllers and models separated to make the code modular. In NodeJS, there is another component called Router, which is responsible for routing the requests to the respective controllers, based on the request URL and the request Method.

ExpressJS is the most common package that provides an easy way to implement this. Below is a very good starter code to structure your project according to this model:

app.js
const bodyParser = require('body-parser');
const express = require('express')
const path = require('path')
const adminRouter = require('./routes/adminRouter')
app = new express()
app.use(bodyParser.urlencoded({extended: true}))
app.use('/admin', adminRouter)
app.listen(3000, () => {
    console.log("Server Listening on Port 3000 ....");
})


routes/adminRouter.js
const adminPost = require("../controllers/adminPost");
const adminMain = require('../controllers/adminMain')
const express = require('express')
const router = express.Router()
router.get('/main', adminMain) //NOTE : This represents a GET request with URL = http://<host>:3000/admin/adminMain
router.post('/adminPost', adminPost) //NOTE : This represents a POST request with URL = http://<host>:3000/admin/adminPost
module.exports = router //NOTE : The router is exported from here


controllers/adminMain.js
const adminMain = (req,res,next) => {
    console.log("Post Request received at admin controller ...");
    console.log("Request Body Parameters Passed in Post Request of the adminMain controller = "+req.query.username);
}
module.exports = adminMain


controllers/adminPost.js
const adminPost = (req, res, next) => {
        console.log("Post Request received at /adminPost in the adminPost Controller");
        console.log("Request Body Parameters Passed in Post Request of the adminPost controller = "+req.body.username);
}
module.exports = adminPost

Implement REST API using NodeJS

To create a REST API, you need to create some additional code along with setting up the Express JS, listener, router etc. Below is an example to create a Simple REST API that supports POST requests and returns a JSON response consisting of a “title” and a “content”.

app.js
const bodyParser = require('body-parser');
const express = require('express')
const adminRouter = require('./routes/adminRouter')
app = new express()
app.use(bodyParser.json())
//The below middleware is required to avoid CORS error, due to the requester and server domains being different, in case they are, which is mostly the case.
app.use((req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', '*') 
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT, PUT') 
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization') 
    next()
})
app.use('/admin', adminRouter)
app.listen(4000, () => {
    console.log("Server Listening on Port 4000 ....");
})

routes/adminRouter.js
const adminPost = require("../controllers/adminPost");
const express = require('express')
const router = express.Router()
router.post('/adminPost', adminPost)
module.exports = router

controllers/adminPost.js
const adminPost = (req, res, next) => {
        console.log("Received the request with content = "+req.body.content);
        res.status(200).json({
            title: 'Things to Explore in Singapore',
            content: 'The most exciting place in Singapore is the Sentosa. \
            It is a small island with a lot of recreations around. There are \
            amazing sculptures and beautiful beaches to relax and rejuvinate.'
        })
}
module.exports = adminPost

Call REST API using axios module

axios is a third party module, that creates an Ajax call to get the response from a REST API. Below is the simple JavaScript code:

      axios('http://localhost:4000/admin/adminPost', {
        'name': 'Animesh',
        'email': 'ani@gmail.com'
     },

     {
        method: "POST"
      })
      .then(res => {
        console.log("Response from axios call = ", JSON.stringify(res));
        this.setState(
          state => ({
            'title' : res.data.title,
            'content': res.data.content
          })
        )
      })

OUTPUT from the console.log

Call REST API using the normal JavaScript fetch()

fetch() is a JavaScript function that allows to make calls to any URL, and get the response in a Promise. It just takes the URL string as argument for GET request, whereas, for POST request, it takes the request BODY as a JS Object, along with the URL, as parameters. Below is an example for POST request. For GET, it works exactly the same way, but just remove the second parameter.

      fetch('http://localhost:4000/admin/adminPost', {
        method: "POST"
      })
      .then(res => { //This is the first promise which returns the raw response, that you need //to convert to json using the res.json() and return it for the next promise
        console.log("response = ", res);
        return res.json()
      })
      .then(resData => { //In this promise, it returns the response data, where you can just //get any of the attribute values as resData.<attribute_name>
          console.log("resData = ", resData);
          this.setState(
              state => ({
                  'title' : resData.title,
                  'content': resData.content
              })
        )
      })

ADD Authentication to REST APIs

There are few steps to implement authentication for REST API calls.

1) Client send a regular API call with username and password, which is already configured in the server for validation.

2) Server validates the credentials.

3) If credentials are correct, it creates a JWT Token (using the jsonwebtoken module’s sign method)

4) Server sends the JWT Token in the response body. It is passed in the body along with a key e.g. “Authorization”

5) Make sure that all the CORS headers have been set at the server side

6) Client receives the response with the “Authorization” key in the body. It stores the token in the localStorage of the browser. If you are using clients, other than browser, store the token in order to use it in the subsequent API calls.

7) In the next call, Client extracts the token from the browser localStorage, or from wherever it is stored in Step 6, and pass that as the value of the “Authorization” header in the request to call the REST service

8) When server receives the request with “Authorization” header, it extracts and validates the token using the jsonwebtoken module’s verify method.

9) If validation succeeds, server sends the response with the right data, otherwise sends back an error.

Server Side Code

=======================================================================================
app.js
=======================================================================================
const bodyParser = require('body-parser');
const express = require('express')
const adminRouter = require('./routes/adminRouter')
const checkJWT = require('./controllers/checkJWT')
const { body } = require('express-validator')
const checkIDPassword = require('./controllers/checkIDPassword');

app = new express()

app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: true}))

//Setting the CORS headers
app.use((req, res, next) => { 
    res.setHeader('Access-Control-Allow-Origin', '*') 
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT, PUT') 
    res.setHeader('Access-Control-Allow-Headers', '*') 
    next()
})

//This defines the API to login with username/password and generate the token for subsequent //calls
app.post('/login', [
    body('username')
    .trim()
    .isEmpty(),
    body('password')
    .trim()
    .isEmpty()
], checkIDPassword)

//API call that requires the token to be present in the request header in the Authorization
app.use('/admin', checkJWT, adminRouter)

//This is for error handling, which you can customize in your own way
app.use((error, req, res, next) => {
    if (error.statusCode) {
        console.log("Error in serving request. Status Code = ", error.statusCode, "Description = ", error.description);
        res.status(error.statusCode).json({
            errorCode: error.statusCode,
            errorDescription: error.description
        })
    }
})

app.listen(4000, () => {
    console.log("Server Listening on Port 4000 ....");
})



=======================================================================================
checkIDPassword.js
=======================================================================================
const { validationResult } = require('express-validator')
const jwt = require('jsonwebtoken')

const checkIDPassword = (req, res, next) => {

//Validation whether username and password is present in the request
    const valErrors = validationResult(req)
    if (!valErrors.isEmpty()) {
        const error = new Error("Please provide Username & Password as part of the request body")
        next(error)
    }

    const username = req.body.username
    const password = req.body.password

    if (password === "P@ssw0rd") {
//Generating the token, if username/password is correct
        const authToken = jwt.sign(
            { 'username': username }, 
            'mysecret-sdfsfsfs9398728hsdiufhwe78rywihuehf',
            { expiresIn: '1h' }
        )

//Adding the Bearer prefix (which is a common practice), and sending the response after //attaching the token to the Authorization header and body
        const bearerToken = 'Bearer ' + authToken
        res.setHeader('Authorization', bearerToken)
        res.status(200).json({
            message: "JWT set successfully in the response header .......",
            Authorization: bearerToken
        })
    } else {
        const error = new Error('User provided wrong credentials!!')
        throw error
    }
   
}

module.exports = checkIDPassword



=======================================================================================
checkJWT.js
=======================================================================================
const jwt = require('jsonwebtoken')
const checkJWT = (req, res, next) => {
    console.log("req.method 1 == ", req.method);
//As per CORS specifications, any POST call is preceded by an OPTIONS call to check if the //resource can be accessed. If the OPTIONS calls fails, then the actual POST call automatically //fails. However, since the OPTIONS call will not have the Authorization header, it is //important to check that and return with success.
    if (req.method == "OPTIONS") {
        next()
    } else {
//Extracting the Authorization Header
        const authHeader = req.get('Authorization')
        if (!authHeader) {
           const error = new Error('Client Not Authorized to access the service!! '+authHeader)
           error.statusCode = 401
           next(error)
        }
       //Separating the Bearer string from the token
        const authToken = authHeader.split(' ')[1]
        if (!authToken) {
            console.log("req.method 3 == ", req.method);
            const error = new Error("Client Not Authorized to access the service!!")
            error.statusCode = 401
            next(error)
        }
    
//The token verification is being done here
        jwt.verify(authToken, 'mysecret-sdfsfsfs9398728hsdiufhwe78rywihuehf', 
        (error, decodedToken) => {
            if (error) {
                console.log("req.method 4 == ", req.method);
                const error = new Error('Token Validation Failed !!')
                error.statusCode = 401
                next(error)
            }
            console.log("req.method 5 == ", req.method);
            next()
        })
    }
}

module.exports = checkJWT



=======================================================================================
adminMain.js
=======================================================================================

const adminMain = (req,res,next) => {

    res.status(200).json({
        name: 'Animesh Banerjee',
        age: 38,
        location: 'Singapore',
        familyMembers: [
            {
                name: 'Moumita Banerjee',
                age: 34,
                relation: 'Spouse'
            },
            {
                name: 'Aishani Banerjee',
                age: 9,
                relation: 'Daughter'   
            },
            {
                name: 'Sudipto Banerjee',
                age: 3,
                relation: 'Son'
            },
            {
                name: 'Laxmi Kanta Banerjee',
                age: 67,
                relation: 'Father'
            }
        ]
    })
}

module.exports = adminMain

Client Side Code (React)

=======================================================================================
app.js
=======================================================================================
import axios from 'axios'
import { Component } from 'react';

class App extends Component {

    state = {
        loginResponse: '',
        serverResponse: '',
        authToken: '',
        tokenRemoveResponse: ''
    }

//Remove Token from Browser localStorage
    removeToken = () => {
        localStorage.removeItem('TESTTOKEN')
        this.setState({tokenRemoveResponse: 'Token Removed!!'})
    }

    getResponse = (url) => {
            axios.post(url,
            {
            'username': 'sdfsdfsfs',
            'password': 'P@ssw0rd'
            },
            {
              method: 'GET',
              headers: {
                Authorization: localStorage.getItem('TESTTOKEN') //Get the token from //localStorage
              }
            })
            .then(response => {
//Checks the request URL. if it is for login, then it expects the token in the response body, //whereas if it is for the API call, it expects a the API response with data.
                if (url.includes('login')) {
                    localStorage.setItem('TESTTOKEN', response.data.Authorization) //Set the //token in browser localStorage
                    this.setState({loginResponse: "Login Successful", authToken: response.data.Authorization})
                } else if(url.includes('main')) {
                    this.setState({serverResponse: JSON.stringify(response.data)})
                } else {
                    this.setState({serverResponse: "Please provide a correct request url"})
                }             
            }
            )
            .catch((error) => {
                console.log("ERROR == ", error)
            })
        }

    render() {
        return(
            <div>
                <button style={{textDecoration: 'none', backgroundColor: 'brown', color: 'white'}} onClick={() => this.getResponse('http://localhost:4000/login')}>Login</button>
                <p>{this.state.loginResponse}</p>
                <hr/>
                <button referrerPolicy='no-referrer' style={{textDecoration: 'none', backgroundColor: 'brown', color: 'white'}} onClick={() => this.getResponse('http://localhost:4000/admin/main')}>Main Request</button>
                <p>{this.state.serverResponse}</p>
                <hr/>
                <button referrerPolicy='no-referrer' style={{textDecoration: 'none', backgroundColor: 'brown', color: 'white'}} onClick={this.removeToken}>Remove Token</button>
                <p>{this.state.tokenRemoveResponse}</p>
            </div>
        )
    }

}

export default App;

This is how the Client looks like

Add Server side validation

You can use the express-validator module to incorporate validation at the server side in NodeJS.

Server Side Code

app.js
const bodyParser = require('body-parser');
const express = require('express')
const adminRouter = require('./routes/adminRouter')
const { body } = require('express-validator')
app = new express()
app.use(bodyParser.json())
app.use((req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', '*') 
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT, PUT') 
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization') 
    next()
})
app.use('/admin', [
    body('name')
    .trim()
    .isEmail()
], adminRouter)
app.listen(4000, () => {
    console.log("Server Listening on Port 4000 ....");
})


routes/adminRouter.js
const adminPost = require("../controllers/adminPost");
const express = require('express')
const router = express.Router()
router.post('/adminPost', adminPost)
module.exports = router


controllers/adminPost.js
const { validationResult } = require('express-validator')
const adminPost = (req, res, next) => {
        const errors = validationResult(req)
        if (!errors.isEmpty()) {
            res.status(422).json({ //422 is the normal response code for validation errors
                message: "The user entered an invalid Email!!"
            })
        }
        console.log("Received the request with content = "+req.body.name);
        res.status(200).json({
            title: 'Things to Explore in Singapore',
            content: 'The most exciting place in Singapore is the Sentosa. \
            It is a small island with a lot of recreations around. There are \
            amazing sculptures and beautiful beaches to relax and rejuvinate.'
        })
}
module.exports = adminPost


Client Side [Below is a code written on React to update the State with the error message]
      axios('http://localhost:4000/admin/adminPost', {
        method: "POST",
        data: {
          name: 'Animesh Banerjee'
        }
      })
      .then(res => {
        console.log("response status is 200 ...");
        this.setState(
          state => ({
            'hasError': false,
            'title' : res.data.title,
            'content': res.data.content
          })
        )
      }).catch((error) => {
          console.log("response status is not 200 ...", error.response);
          this.setState(
            state => ({
              'hasError': true,
              'message' : error.response.data.message,
              'content': ''
            })
          )
      })

//NOTE : You can get the response inside the catch block using the error.response object, then you can call error.response.data.message to get the exact string, which was set at the Server Side Code in the controllers/adminPost.js

Working with MongoDB, Mongoose and NodejS Models

MongoDB is a document based Database that comes with the Mongoose module for NodeJS, and is very easy to integrate with NodeJS. It has become extremely popular for the ease of use, and its flexibility. Below are the main steps for integration:

1)Create a DB Cluster, Database and a Collection in mongoDB Atlas. You can use a local installation as well, but using the Cloud Based solution is the easiest. It provides free storage upto 512 MB, which is really good for testing and learning.

2)Install mongoose package in the NodeJS Project

npm install mongoose

3)Create the Model in the NodeJS Project

models/Student.js
const mongoose = require('mongoose')
const studentSchema = mongoose.Schema({
    name: {
        type: String,
        required: true
    },
    class: {
        type: String,
        required: true
    },
    school: {
        type: String,
        required: true
    }
}, {timestamps: true}) //The timestamps object will insert the createdAt and updatedAt into the DB for each entry automatically
module.exports = mongoose.model('Student', studentSchema)

4)Get the Connection URL from the mongoDB Atlas. Note that you need to allow connection from you Client IP [Network Access tab in Atlas Dashboard]. Click on the Connect button on your Cluster to get the Connection URL.

5)Create the Connection to MongoDB in app.js with the previous URL in Step 4

const mongoose = require('mongoose')
mongoose.connect('mongodb+srv://<yourusername>:<yourpassword>@cluster0.bgyrx.mongodb.net/<yourDBName>?retryWrites=true&w=majority')
.then(result => {
    app.listen(4000, () => {
        console.log("Server Listening on Port 4000 ....");
    })
})
.catch(error => {
    console.log("Some problem happened in the DB Connection : ", error);
})

6)Create the JavaScript Object as per the Schema defined in the Model

const StudentModel = require('../models/Student')
const student = new StudentModel({
    name: 'Aishani',
    class: '4',
    school: 'DPS'
})

7)Call save(), update() or remove() operations on the Object that you got from Step 6 to create a new Object, update an existing one or to remove one from the Database respectively.

        student.save()
        .then(() => {
            res.status(200).json({
                result: 'Student Created Successfully'
            })
        })
        .catch(error => {
            console.log('Problem Happened in Creating Student ',error);
        })

There are several other important functions exposed by mongoose Model, that can be very helpful in working with the MongoDB.

  1. Model.deleteMany()
  2. Model.deleteOne()
  3. Model.find()
  4. Model.findById()
  5. Model.findByIdAndDelete()
  6. Model.findByIdAndRemove()
  7. Model.findByIdAndUpdate()
  8. Model.findOne()
  9. Model.findOneAndDelete()
  10. Model.findOneAndRemove()
  11. Model.findOneAndReplace()
  12. Model.findOneAndUpdate()
  13. Model.replaceOne()
  14. Model.updateMany()
  15. Model.updateOne()

Got to this link to get detailed explanation of each of these functions : https://mongoosejs.com/docs/queries.html

Pagination with MongoDB Data

When dealing with either displaying posts in your page, or several news articles, then pagination is a must, so that the user gets limited data per page, and has the flexibility to move to the next or previous page. This can be very easily done using mongoose Models. Consider the below Models and variables already created.

Post – Model

totalItems – Total number of posts

currentPage – Get the current page from request parameter

perPage – Number of posts/items to show or paginate per page

Post.find()
  .countDocuments()
  .then(count => {
      totalItems = count;
      return Post.find()
                .skip((currentPage - 1) * perPage)
                .limit(perPage)
  })

Best Practice for Error Handling

It is always recommended that you don’t throw error in all the JS files. Instead, just use all the JS files to set a statusCode and a errorMessage/errorDescription to the Error Object, that you need to create and pass it as an argument to the next(error) call. This will take the control back to the calling script, and ultimately to app.js.

        if (!errors.isEmpty()) {
            const error = new Error('Validation Error Happened!!')
            error.statusCode = 422
            error.description = "Validation Error Description ...."
            next(error)
        }

In app.js, write a generic route at the bottom of all the routes(that will match all URLs), and check whether the statusCode is empty. If not empty, then set the statusCode as received, along with a json response with the statusCode and errorMessage set as a Javascript Object.

app.use('/', (error, req, res, next) => { //write this at the bottom of the app.js file, so //that any other routes are handled normally. In case the control comes to this route due to //the next(error) call, then set the response Code here, and return the json response //accordingly.
    if (error.statusCode) {
        console.log("Error in serving request. Status Code = ", error.statusCode, "Description = ", error.description);
        res.status(error.statusCode).json({
            errorCode: error.statusCode,
            errorDescription: error.description
        })
    } else {
        res.status(500).json({ //The control will come here, if somewhere in other scripts, you //have forgotten to set the status code, but just forwarded the error with next(error)
            errorCode: 500,
            errorDescription: "Some Error happened at Server"
        })
    }
})

Configure NodeJS for allowing file upload

1) Download the multer npm package

npm install multer

2) import the multer and path package

const multer = require('multer')
const path = require('path')

3) Configure the destination and filename to store the file in server

var storage = multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, path.join(__dirname,'../images')) //cb is the callback method | null means no //error
    },
    filename: function (req, file, cb) {
      const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9)
      cb(null, file.fieldname + '-' + uniqueSuffix + '.jpg') //cb is the callback method | null //means no error
    }
  })

var upload = multer({ storage: storage })

4) Create the middleware in the router or express app variable, to extract the file from the request

router.post('/adminUpload', adminUpload, upload.single('profilePhoto')) // Here profilePhoto is //the fieldname from the input form, in which the file is passed.

Use the ‘path’ module to construct platform independent local paths

const express = require('express')
app = new express()
app.listen(3000, () => {
console.log('NodeJS started listening on port 3000')
})
const path = require('path')
app.get('/', (req, res) => {
res.sendFile( path.join(__dirname,'/index.html'))
})
//Here __dirname is a special variable that denotes the path //of the current file from which this code is invoked.

Fetch JSON Data and store into MongoDB using NodeJS

Step1. Install the module node-fetch : npm install node-fetch

Step2. Use the below code:

const fetch = require('node-fetch')
const mongoose = require('mongoose')
const TaxiStand = require('./models/TaxiStand')
mongoose.connect("mongo_URL")
.then(result => { 
fetch('http://datamall2.mytransport.sg/ltaodataservice/TaxiStands', 
{ 
 method: "GET", 
 headers: 
  { "AccountKey" : "6S70dxfYT4CyKHJEdwco2g==" } 
}) .then(res => { 
 return res.json() 
}) .then(resData => { 
let resDataArr = resData["value"] 
resDataArr.forEach(taxiStand => 
  { let standCode = taxiStand["TaxiCode"] 
    let latitude = taxiStand["Latitude"] 
    let longitude = taxiStand["Longitude"] 
    let hasBarrier = taxiStand["Bfa"] 
    let standName = taxiStand["Name"] 
    let standType = taxiStand["Type"] 
new TaxiStand({ 
 standName : standName, 
 standType : standType, 
 standCode : standCode, 
 hasBarrier : hasBarrier, 
 latitude : latitude, 
 longitude : longitude
}).save() 
}); 
})
}).catch(error => { 
  console.log("Some problem happened in the DB Connection : ", error);
})

How to return a promise from an async function

If you are making a DB call, it will take some time to return the response. In that case, the function has to be handled differently. Let’s say below function is trying to create a customer in MongoDB.

const saveNewCustomer = (req, res) => {
    console.log("request body = ", req.body.custName);
    const name = req.body.custName
    const store = req.body.storeName
    const addr = req.body.address
    const phone = req.body.phoneNumber
    saveNewCustomerToDB(name, store, addr, phone)
}

const saveNewCustomerToDB = (custName, storeName, address, phoneNumber) => {
    const customer = new Customer({
        'custName': custName,
        'storeName': storeName,
        'address': address,
        'phoneNumber': phoneNumber
    })
    customer.save()
    .then(() => {
        console.log("New customer created successfully");
    })
    .catch(error => {
        console.log('Problem Happened in Creating Customer ',error);
    })
}

The problem with above logic is that you cannot get the result of DB update/save in the calling function i.e in saveNewCustomer function, since the customer.save() is an async function and will immediately return, but continue doing the save() asynchronously. So the calling function i.e saveNewCustomer will never get the result of the save().

To deal with such scenario, you need to define the saveNewCustomerToDB as an async function, and add await keyword while calling the customer.save() and return a Resolved Promise or a Rejected Promise, as is the case, from the then() and catch() functions respectively.

Here is the code for reference.

const saveNewCustomer = (req, res) => {
    console.log("request body = ", req.body.custName);
    const name = req.body.custName
    const store = req.body.storeName
    const addr = req.body.address
    const phone = req.body.phoneNumber
    saveNewCustomerToDB(name, store, addr, phone)
    .then(() => {
        res.status(200).json({
            result: 'Customer Created Successfully'
        })
    })
    .catch((error) => {
        res.status(500).json({
            result: 'Could not Create Customer'+error
        })
    })
}

const saveNewCustomerToDB = async (custName, storeName, address, phoneNumber) => {
    const customer = new Customer({
        'custName': custName,
        'storeName': storeName,
        'address': address,
        'phoneNumber': phoneNumber
    })
    console.log("Before await in the saveNewCustomerToDB .....");
    await customer.save()
    .then(() => {
        console.log("New customer created successfully... Now it result will be returned as null");
        return Promise.resolve()
    })
    .catch(error => {
        console.log('Problem Happened in Creating Customer ',error);
        return Promise.reject(error)
    })
}

Handle a Promise from DB calls

If you call a mongoDB, it takes some time to return the response. This is how you get the response or error in the calling function.

//Calling Function
const findCustomer = (req, res) => {

    console.log("phone number=",req.body.phoneNumber);
    findCustomerFromDB(req.body.phoneNumber)
    .then((output) => { //This is where you get the response
        res.status(200).json({
            'customers': output
        })
    })
    .catch(error => {
        res.status(404).json({
            message: 'No Customer Found '+error
        })
    })

}


//Called Function which is returning the promise with an async/await
const findCustomerFromDB = async (phoneNumber) => {
    return await Customer.find({ phoneNumber: phoneNumber }).exec()
}

Leave a Reply

Your email address will not be published. Required fields are marked *