Download as pdf or txt
Download as pdf or txt
You are on page 1of 21

23.

Introduction to NodeJS

Table of Content
1. Introduction to NodeJS

2. NPM Basics

3. Introduction to ExpressJS

4. API and HTTP Request Types

1. Introduction to NodeJS
Node.js is an open-source server-side runtime environment built on Chrome's V8
JavaScript engine. It provides an event-driven, non-blocking (asynchronous) I/O and
cross-platform runtime environment for building highly scalable server-side applications
using JavaScript.
Node.js can be used to build different applications such as command line, web, real-
time chat, REST API server, etc.

NodeJS Process Model

Traditional Web Server Model


In the traditional web server model, each request is handled by a dedicated
thread from the thread pool. If no thread is available in the thread pool at any
point of time then the request waits till the next available thread. Dedicated
thread executes a particular request and does not return to the thread pool until
it completes the execution and returns a response.

23. Introduction to NodeJS 1


Node.js Process Model
Node.js processes user requests differently when compared to a traditional web
server model. Node.js runs in a single process and the application code runs in
a single thread and thereby needs less resources than other platforms. All the
user requests to your web application will be handled by a single thread and all
the I/O work or long running job is performed asynchronously for a particular
request. So, this single thread doesn't have to wait for the request to complete
and is free to handle the next request. When asynchronous I/O work completes
then it processes the request further and sends the response.
An event loop is constantly watching for the events to be raised for an
asynchronous job and executing callback function when the job completes.
Internally, Node.js uses libev for the event loop which in turn uses internal C++
thread pool to provide asynchronous I/O.
The following figure illustrates asynchronous web server model using Node.js.

23. Introduction to NodeJS 2


NodeJS Module
Each module in Node.js has its own context, so it cannot interfere with other
modules or pollute the global scope. Also, each module can be placed in a separate
.js file under a separate folder.

Node.js implements the CommonJS modules standard. CommonJS is a group of


volunteers who define JavaScript standards for web server, desktop, and console
application.

Types of Modules:

1. Core Modules

Node.js is a light weight framework. The core modules include bare minimum
functionalities of Node.js. These core modules are compiled into its binary
distribution and load automatically when Node.js process starts. However, you
need to import the core module first in order to use it in your application.

Core Module Description

http module includes classes, methods and events to create Node.js


http
http server.
url url module includes methods for URL resolution and parsing.

querystring querystring module includes methods to deal with query string.

23. Introduction to NodeJS 3


path path module includes methods to deal with file paths.

fs module includes classes, methods, and events to work with file


fs
I/O.
util util module includes utility functions useful for programmers.

var http = require('http');

var server = http.createServer(function(req, res){

//write code here

});

server.listen(5000);

2. Node.js Local Module

Local modules are modules created locally in your Node.js application. These
modules include different functionalities of your application in separate files and
folders.

var log = {
info: function (info) {
console.log('Info: ' + info);
},
warning:function (warning) {
console.log('Warning: ' + warning);
},
error:function (error) {
console.log('Error: ' + error);
}
};

module.exports = log

var myLogModule = require('./Log.js');

myLogModule.info('Node.js started');

The module.exports is a special object which is included in every JavaScript file


in the Node.js application by default. The module is a variable that represents

23. Introduction to NodeJS 4


the current module, and exports is an object that will be exposed as a module.
So, whatever you assign to module.exports will be exposed as a module.

2. NPM Basics
Node Package Manager (NPM) is a command line tool that installs, updates or
uninstalls Node.js packages in your application. It is also an online repository for open-
source Node.js packages. The node community around the world creates useful
modules and publishes them as packages in this repository.
Official website: https://www.npmjs.com
NPM is included with Node.js installation.

Using NPM Commands

1. Install package: npm install -g <package name>

2. Update package: npm update <package name>

3. Uninstall package: npm uninstall <package name>

Use the -D flag to do the above changes with dev dependencies.

4. Create an empty Node project with npm: npm -init

3. Introduction to Express.JS
Express.js is a web application framework for Node.js. It provides various features that
make web application development fast and easy which otherwise takes more time
using only Node.js.

Advantages of Express.js

1. Makes Node.js web application development fast and easy.

2. Easy to configure and customize.

3. Allows you to define routes of your application based on HTTP methods and URLs.

4. Includes various middleware modules which you can use to perform additional tasks
on request and response.

23. Introduction to NodeJS 5


5. Easy to integrate with different template engines like Jade, Vash, EJS etc.

6. Allows you to define an error handling middleware.

7. Easy to serve static files and resources of your application.

8. Allows you to create REST API server.

9. Easy to connect with databases such as MongoDB, Redis, MySQL

install express
npm install -g express

const express=require('express');
const app=express();

app.get('/',function(req,res)
{
res.send('Hello World!');
});

app.listen(3000,function() {});

4. API and HTTP Request Types

An API (Application Programming Interface), as the name suggests, is an interface that


defines the interaction between different software components. Web APIs define what
requests can be made to a component (for example, an endpoint to get a list of books),
how to make them (for example, a GET request), and their expected responses.

There are a few types of HTTP methods that we need to grasp before building a REST
API. These are the methods that correspond to the CRUD tasks:

POST : Used to submit data, typically used to create new entities or edit already
existing entities.

GET : Used to request data from the server, typically used to read data.

23. Introduction to NodeJS 6


: Used to completely replace the resource with the submitted resource, typically
PUT

used to update data.

DELETE : Used to delete an entity from the server.

Assignments:
1. Build a GET API service to return a random number between 1 to 6

2. Build an API service to do POST request with the following operations:

a. sum of n numbers : POST /sum

b. average of n numbers : POST /average

23. Introduction to NodeJS 7


24. Dotenv, Router, Middleware,
and MVC

Table of Content
1. Dotenv

2. Express Router

3. MVC Architecture

4. Middleware

1. Dotenv
Environment variables are variables that are set outside of a program, often through a
cloud provider or operating system.
In Node, environment variables are a great way to securely and conveniently configure
things that don't change often, like URLs, authentication keys, and passwords.
Environment variables are supported out of the box with Node and are accessible via
the env object (which is a property of the process global object.)
DotEnv is a lightweight npm package that automatically loads environment variables
from a .env file into the process.env object.
To use DotEnv, first install it using the command: npm i dotenv . Then in your app,
require and configure the package like this: require('dotenv').config() .

2. Express Router
Use the express.Router class to create modular, mountable route handlers. A Router
instance is a complete middleware and routing system; for this reason, it is often
referred to as a “mini-app”.

24. Dotenv, Router, Middleware, and MVC 1


const express = require('express')
const router = express.Router()

// middleware that is specific to this router


router.use((req, res, next) => {
console.log('Time: ', Date.now())
next()
})
// define the home page route
router.get('/', (req, res) => {
res.send('Birds home page')
})
// define the about route
router.get('/about', (req, res) => {
res.send('About birds')
})

module.exports = router

const birdsRouter = require('./birds')

// ...

app.use('/birds', birdsRouter)

3. MVC Architecture
MVC is simply a design or architectural pattern used in software engineering. While this
isn’t a hard rule, but this pattern helps developers focus on a particular aspect of their
application, one step at a time.
The main goal of MVC is to split large applications into specific sections that have their
own individual purpose.

1. Model
As the name implies, a model is a design or structure. In the case of MVC, the
model determines how a database is structured, defining a section of the application
that interacts with the database. This is where we will define the properties of a user
that will be store in our database.

2. View

24. Dotenv, Router, Middleware, and MVC 2


The view is where end users interact within the application. Simply put, this is where
all the HTML template files go.

3. Controller

The controller interacts with the model and serves the response and functionality to
the view. When an end user makes a request, it’s sent to the controller which
interacts with the database.

4. Middleware
Express is a routing and middleware web framework that has minimal functionality of its
own: An Express application is essentially a series of middleware function calls.
Middleware functions are functions that have access to the request object ( req ),
the response object ( res ), and the next middleware function in the application’s
request-response cycle. The next middleware function is commonly denoted by a
variable named next .
Middleware functions can perform the following tasks:

Execute any code.

Make changes to the request and the response objects.

End the request-response cycle.

Call the next middleware function in the stack.

If the current middleware function does not end the request-response cycle, it must
call next() to pass control to the next middleware function. Otherwise, the request will
be left hanging.

This example shows a middleware function with no mount path. The function is
executed every time the app receives a request.

const express = require('express')


const app = express()

app.use((req, res, next) => {


console.log('Time:', Date.now())
next()
})

24. Dotenv, Router, Middleware, and MVC 3


This example shows a middleware function mounted on the /user/:id path. The
function is executed for any type of HTTP request on the /user/:id path.

app.use('/user/:id', (req, res, next) => {


console.log('Request Type:', req.method)
next()
})

This example shows a route and its handler function (middleware system). The
function handles GET requests to the /user/:id path.

app.get('/user/:id', (req, res, next) => {


res.send('USER')
})

Here is an example of loading a series of middleware functions at a mount point,


with a mount path. It illustrates a middleware sub-stack that prints request info for
any type of HTTP request to the /user/:id path.

app.use('/user/:id', (req, res, next) => {


console.log('Request URL:', req.originalUrl)
next()
}, (req, res, next) => {
console.log('Request Type:', req.method)
next()
})

Route handlers enable you to define multiple routes for a path. The example below
defines two routes for GET requests to the /user/:id path. The second route will
not cause any problems, but it will never get called because the first route ends the
request-response cycle.

This example shows a middleware sub-stack that handles GET requests to


the /user/:id path.

app.get('/user/:id', (req, res, next) => {


console.log('ID:', req.params.id)
next()

24. Dotenv, Router, Middleware, and MVC 4


}, (req, res, next) => {
res.send('User Info')
})

// handler for the /user/:id path, which prints the user ID


app.get('/user/:id', (req, res, next) => {
res.send(req.params.id)
})

Assignments
1. Build a Product Route - /product

Product Schema:

productId String

title String

price Number

1. POST /add (pass data in body)

2. GET /

3. DELETE /:productId

4. PUT /:productId (pass data in body)

2. Build a Review Route - /review

Review Schema:

reviewId String

userId String

productId String

reviewText String

1. POST /add (pass data in body)

2. GET /getAll/:productId

24. Dotenv, Router, Middleware, and MVC 5


3. DELETE /:reviewId

4. PUT /:productId (pass data in body)

24. Dotenv, Router, Middleware, and MVC 6


25. MongoDB and Mongoose

Table of Content
1. MongoDB

2. Mongoose

3. Save data into MongoDB database using APIs

1. MongoDB
MongoDB is a rich open-source document-oriented and one of the widely recognised NoSQL database. It is written in C++
programming language.

Important Terms

Database

Database is a physical container for collections. Each database gets its own set of files on the file system. A single
MongoDB server typically has multiple databases.

Collection

Collection is a group of documents and is similar to an RDBMS table. A collection exists within a single database.
Collections do not enforce a schema. Documents within a collection can have different fields.

Document
A document is a set of key-value pairs. Documents have dynamic schema. Dynamic schema means that documents in the
same collection do not need to have the same set of fields or structure, and common fields in a collection’s documents may
hold different types of data.

BSON stands for Binary Javascript Object Notation. It is a binary-encoded serialization of JSON documents. BSON has been extended to add some
optional non-JSON-native data types, like dates and binary data.

Data Types
MongoDB supports many datatypes such as:

25. MongoDB and Mongoose 1


String − This is the most commonly used datatype to store the data. String in MongoDB must be UTF-8 valid.

Integer − This type is used to store a numerical value. Integer can be 32 bit or 64 bit depending upon your server.

Boolean − This type is used to store a boolean (true/ false) value.

Double − This type is used to store floating point values.

Arrays − This type is used to store arrays or list or multiple values into one key.

Timestamp − This can be handy for recording when a document has been modified or added.

Object − This datatype is used for embedded documents.

Null − This type is used to store a Null value.

Date − This datatype is used to store the current date or time in UNIX time format. You can specify your own date time by
creating object of Date and passing day, month, year into it.

Object ID − This datatype is used to store the document’s ID.

Binary data − This datatype is used to store binary data.

Code − This datatype is used to store JavaScript code into the document.

Regular expression − This datatype is used to store regular expression.

Create your MongoDB Database server

We will be using Atlas to build our MongoDB server. Follow these steps to setup a free server.

Get started with MongoDB Atlas


This article will guide you on how to get started with MongoDB Atlas. 2. Click on Start Free and Complete the
form with your email, name, password, accept terms of services and hit the button that says Get started free
3. Then you will be taken to a new page.
https://medium.com/nerd-for-tech/get-started-with-mongodb-atlas-dbb734726a7f

2. Mongoose

25. MongoDB and Mongoose 2


Mongoose is an object modeling tool for MongoDB and Node.js. What this means in practical terms is that you can define your data
model in just one place, in your code. It allows defining schemas for our data to fit into, while also abstracting the access to
MongoDB. This way we can ensure all saved documents share a structure and contain required properties.

Important Terms

Fields
Fields’ or attributes are similar to columns in a SQL table.

Schema

While Mongo is schema-less, SQL defines a schema via the table definition. A Mongoose ‘schema’ is a document data
structure (or shape of the document) that is enforced via the application layer.

Models
Models’ are higher-order constructors that take a schema and create an instance of a document equivalent to records in a
relational database.

Getting Started with Mongoose

npm i mongoose

Connecting NodeJS with MongoDB Database using mongoose

const mongoose = require("mongoose"); // import mongoose

mongoose
.connect(
"MONGODB_CONNECTION_STRING", // pass in your connection string here
{
useNewUrlParser: true, // default recommended options
useUnifiedTopology: true,
}
)
.then(e => console.log("MongoDB ready"))
.catch(console.error); // If you see an error you probably didn't put in the correct connection string/password

Make sure to replace <password> with the password you created and change myFirstDatabase to the name of the database
you created in step one.

Creating Models
Each collection must have a corresponding model associated with it. For example, if we are storing users in our database, we
must create a user model so that Mongoose knows what fields each user has.
Create a new folder called models. In this f, make a file called User.js. This model will contain all the fields needed to create a
user.
Creating a new model is easy with mongoose.js:

const { model, Schema } = require("mongoose");

const User = new Schema({ // The Schema constructor is used to define new models
firstName: String, // You can use type constructors to define field types
middleName: {
type: String,
default: "", // Middle name has a default value of ""
},
lastName: String,
age: Number,
email: {
type: String,
required: true, // All fields are optional unless you specify otherwise

25. MongoDB and Mongoose 3


},
});

module.exports = model("user", User); // Export the Schema as a mongoose model

Creating Documents

const User = require("./models/User"); // import the User model

const newUser = new User({


// We can create new documents by using the model as a constructor
firstName: "Jimmy",
middleName: "Joseph",
lastName: "John",
age: 42,
email: "jimmy.john@email.com",
});

newUser.save().then(doc => {
console.log("User added to the database");
});

Querying the Database

.find()

.find() is a method that you can call from an exported model, like User. The snippet below demonstrates one way you can
use the .find() method:

const User = require("./models/User"); // Import the User model

const findAllUsers = async () => {// Creates an async function since .find() returns a Promise
const allUsers = await User.find(); // Make sure to use await
console.log(allUsers);
};

findAllUsers();

Find with parameters

const findUserByFirstName = async firstName => { // take in firstName as a parameter


// pass in firstName into .find()
const users = await User.find({ firstName }); // Note this syntax is the same as { firstName: firstName }
console.log(users);
};

findUserByFirstName("Luke"); // Find all users who's firstName is "Luke"

💡 Note: find() always returns an array of documents. Use findOne() when you only need to get one document from
your database.

find with comparison

const findUsersOlderThan = async number => {


const usersOlderThan50 = await User.find({ age: { $gt: number } }); // You can replace $gt with $gte to find users who are at lea
console.log({ usersOlderThan50 });
};
findUsersOlderThan(50); // finds all users older than 50 years

Comparison operators always start with $

$eq

25. MongoDB and Mongoose 4


Matches values that are equal to a specified value.
$gt Matches values that are greater than a specified value.
$gte Matches values that are greater than or equal to a specified value.
$in Matches any of the values specified in an array.
$lt Matches values that are less than a specified value.
$lte Matches values that are less than or equal to a specified value.
$ne Matches all values that are not equal to a specified value.
$nin Matches none of the values specified in an array.

Updating Documents

const User = require("./models/User"); // Import the User model

const incrementAge = async firstName => {


const user = await User.findOne({ firstName }); // Find the user by firstName
if (!user) {
throw new Error("User not found"); // If no user is found, throw an error
}
user.age++; // Mongoose allows you to directly modify the document
const result = await user.save(); // Saves the document to the database
console.log(result);
};
incrementAge("Jimmy"); // Increment Jimmy's age

You first need to fetch the document you want to change. This example uses the firstName field to get the document.

In real-world applications, you may want to query by id or another unique field.

After fetching the correct document, you can directly mutate the object and reassign it to any value (as long as it’s the
correct data type).

Don’t forget to call the .save() method to save the updated document in the database.

Deleting Documents
The following code sample demonstrates two ways you can delete a document from MongoDB:

const User = require("./models/User"); // Import the User model

const deleteUserByFirstName = async firstName => {


await User.deleteOne({ firstName }); // .deleteOne() won't do anything if the user isn't in the database
const allUsers = await User.find();
console.log(allUsers); // console.log all the users after the deletion
};

const deleteUserByFirstName2 = async firstName => {


const user = await User.findOne({ firstName }); // find the given user
if (!user) {
throw new Error("User not found"); // If no user is found, throw an error
}
await user.delete();
const allUsers = await User.find();
console.log(allUsers);
};

deleteUserByFirstName("Luke"); // Deletes Luke from the database

This snippet shows two ways to delete a document in MongoDB. The first function is much shorter and doesn’t require
error handling, while the second one does. Depending on your application, one function may suit you better than the
other.

.deleteOne() takes in a parameter just like .findOne() or .find(). You can still use comparison operators and other find
operators.

25. MongoDB and Mongoose 5


It is important to note that .deleteOne() is a method that can only be called on a model like User (notice the
capitalization). On the other hand, .delete() can only be called on documents like the user variable.

Assignments
1. Build a Database with the following schema and Build a Product Route - /product

Product Schema:

productId ObjectId

title String

price Number

1. POST /add (pass data in body)

2. GET /

3. DELETE /:productId

4. PUT /:productId (pass data in body)

2. Build a Database with the following schema and Build a Review Route - /review

Review Schema:

reviewId ObjectId

userId ObjectId

productId ObjectId

reviewText String

1. POST /add (pass data in body)

2. GET /getAll/:productId

3. DELETE /:reviewId

4. PUT /:productId (pass data in body)

25. MongoDB and Mongoose 6


26. Authentication (Backend)

Table of Content
1. JWT access token and refresh tokens

1. JWT access token and refresh tokens


JSON Web Token
JSON Web Token (JWT) is an open standard based on JSON to create access
tokens that allow the use of application or API resources. This token will incorporate
the information of the user who needs the server to identify it, as well as additional
information that may be useful (roles, permissions, etc.).
It may also have a validity period. Once this validity period has elapsed, the server
will no longer allow access to resources with this token. In this step, the user will
have to get a new access token by reauthentication or with some additional
method: refresh token.

Types of Token
There are many types of tokens, although in authentication with JWT the most
typical are access token and refresh token.

Access token: It contains all the information the server needs to know if the
user / device can access the resource you are requesting or not. They have
usually expired tokens with a short validity period.

Refresh token: The refresh token is used to generate a new access token.
Typically, if the access token has an expiration date, once it expires, the user
would have to authenticate again to obtain an access token. With refresh token,
this step can be skipped and with a request to the API get a new access token
that allows the user to continue accessing the application resources.

26. Authentication (Backend) 1


Flow
After an access token is generated, sometimes you might have to renew the old
token due to expiration or security concerns. You can renew an access token using
a refresh token, by issuing a REST call to the Token API with the following
parameters. A refresh token has to be obtained before using it with a grant type
such as the authorization code or password grant type. Using the obtained refresh
token, you can obtain a new access token without having to go through any other
additional steps.
The diagram below illustrates the refresh token grant flow.

26. Authentication (Backend) 2

You might also like