0% found this document useful (0 votes)
10 views78 pages

Express JS- Part2

Uploaded by

P.Padmini Rani
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
Download as pptx, pdf, or txt
0% found this document useful (0 votes)
10 views78 pages

Express JS- Part2

Uploaded by

P.Padmini Rani
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1/ 78

Express JS

Cont..
CRUD Operations
 Create:
 Insert Document – Demo
 Mongoose library offers several functions to
perform various CRUD (Create-Read-
Update-Delete) operations.
 Inserting a document into the
collection
 To insert a single document to MongoDB,
use the create() method. It will take
the document instance as a parameter.
Insertion happens asynchronously and any
operations dependent on the inserted
document must happen by unwrapping the
promise response.
 We can insert a new document into our
myNotes Collection using the below code:
exports.newNotes = async (req, res) => {
try {
const noteObj = {
notesID: 7558, name: 'Mathan', data:
'Mongo Atlas is very easy to configure and
use.',
};
const newNotes = await
NotesModel.create(noteObj);
console.log(newNotes);
}
catch (err) {
console.log(err.errmsg);
}
 In line 1, a new async function newNotes
is created with request and response
objects as parameters.
 In line 3, a new object is created with the
name noteObj with all the necessary keys
that need to be inserted.
 In line 8, we are referring to
the NotesModel which we had created
previously, and then making use of the
create() method to insert the document
into the collection. This will insert the
documents into the collection based on
the schema and will return the
documents which got inserted to the
const newNotes.
Try catch block will ensure all the
exceptions are handled in the
code.
In line 9, after successful
insertion, you will get the
following output in the console:
Insert multiple documents – Demo

 In order to insert multiple documents into


a collection, we can use any one of the
following two methods: insert()
or insertMany(). The syntax for inserting
multiple documents into a collection is:
 Model.insert([document1, document2]);
or
 Model.insertMany([document1,

document2]);
 Let us now insert more documents into our myNotes
collection using the below code:
 exports.newNotes = async (req, res) => {
 try {
 const noteObj = [
 {notesID: 7555, name: 'Mathan', data:
'This includes macOS package notarization and a change
in configuration... ', },
 {notesID: 7556, name: 'Sam', data: 'AMD
processor support in android studio.', },
 {notesID: 7557, name: 'Mathan', data: 'MERN',
},
 ];
 const newNotes = await NotesModel.create(noteObj);
console.log(newNotes);
 }
 catch (err) {
 console.log(err.errmsg);
 }
 In line 1, a new async function newNotes is
created with request and response objects
as parameters.
 In line 3, a new array of objects is created
with the name noteObj with all the
necessary keys that need to be inserted.
 In line 16, we are referring to the same
NotesModel which we had created earlier.
We can now make use of the
create() method to insert the documents
into the collection. It will insert the
documents into the collection based on the
schema and will return the documents
which got inserted to the const newNotes.
 Try catch block will ensure all the
exceptions are handled in the code.
In line 17, after successful
insertion, you will get the following
output in the console:
Read document(s)
 Documents can be retrieved through find,
findOne, and findById methods.
 Let us now retrieve all the documents that we
have inserted into our myNotes Collection.
exports.getNotes = async (req, res) => { try {
const notes = await NotesModel.find({},
{ _id: 0, __v: 0 });
if(notes.length > 0) {
console.log(notes);
}
}
catch (err) {
console.log(err.errmsg);
}
};
In line 1, a new async function getNotes
is created with request and response
objects as parameters.
In line 3, we are referring to the same
NotesModel which we had created
earlier and made use of the
find() method to fetch the document(s)
from the collection. The retrieved
documents will be available in the const
notes.
In line 4, we are ensuring the data by
checking the length and displaying the
returned data in the console.
Try catch block will ensure all the
exceptions are handled in the code.
On successful retrieval of the
documents, you will get the following
output in the console:
Retrieving data based on the condition
 Let us try to retrieve notes details based on
notesID from the myNotes Collection using
the below code:
 exports.getNotes = async (req, res) =>
{ try {
 const notes = await
NotesModel.find({ notesID: 7555 },
 { _id: 0, __v: 0 });
 if (notes.length > 0)
{ console.log(notes); }
}
 catch (err) {
 console.log(err.errmsg); }
 };
 In line 1, a new async function getNotes is
created with request and response objects as
parameters.
 In line 3, we are referring to the same
NotesModel which we had created earlier and
made use of the find() method to fetch the
document(s) from the collection by providing
the condition(s) based on which documents
should be retrieved. The retrieved documents
will be available in the const notes.
 In line 4, we are ensuring the data by
checking the length and displaying the
returned data in the console.
 Try catch block will ensure all the exceptions
are handled in the code.
On successful retrieving of the
document, you will get the
following output in the console:
Update document(s)
 We will update the details of the myNotes collection
using the below code:
 exports.updateNotes = async (req, res) => {
 try {
 const noteObj = {
 name: 'Mathan',
 data: 'Updated notes',
 };
 const notes = await NotesModel.findOneAndUpdate(

 { notesID: 7555 },
 noteObj,
 {
 new: true, //to return new doc back
 runValidators: true, //to run the validators which
specified in the model
 }
if(notes != null) {
console.log(notes);
}
}
catch (err) {
console.log(err.errmsg);
}
};
 In line 1, a new async function
updateNotes is created with request and
response objects as parameters.
 In line 3, a new array of objects is created
with the name noteObj with all the
necessary keys that need to be updated.
 In line 8, we are referring to the same
NotesModel which we had created earlier
and made use of
the findOneAndUpdate() method to
find and update one document in the
collection. It will update the document in
the collection based on the schema and
will return the document which got
updated to the const notes.
The parameters of
findOneAndUpdate() method are:
The condition based on which the
document should be updated.
The new values to be updated.
Additional options to return the
updated document and to validate
the values based on the schema
definition.
Try catch block will ensure all the
exceptions are handled in the
code.
In line 18. On successful updating
of the document, you will get the
following output in the console.
Delete document(s)
The below code shows how to delete
the contents of myNotes collection:
exports.deleteNotes = async (req,
res, err) => {
const delDet = await
NotesModel.deleteOne({
notesID: 7555 });
console.log(delDet);};
In line 1, a new async function
deleteNotes is created with the
request, response, and error objects
as parameters.
In line 2, we are referring to the
same NotesModel which we had
created earlier and made use
of deleteOne() method to delete
the document from the collection
based on the condition and will
return the details about the delete
operation performed, which is
initialized to the const delDet.
In line 3, on the successful
deletion of the document, you will
get the following output in the
console.
API Development
Introduction
We are going to learn how to
create a set of APIs with all CRUD
operations.
This project covers the following:
Create a web server
Routing
Middleware
Database connectivity to MongoDB
using mongoose
Atypical folder structure with all
the necessary folders will look like
the below image:
The following describes the folder
structure of the project:
Controller – Business logic and
Database operations of the
application.
Model – MongoDB schema and model.
Routes - All the routes that
are created for the application.
Utilities – Helper files for the
application. E.g. Custom validators,
loggers, etc.
app.js – The starting point of the
application.
 app.js file
 Application execution will start from the app.js file.
 All the necessary imports and middlewares need to
be configured in this file.
 In the app.js, include the following code:
 const express = require('express');
 const bodyparser = require('body-parser');
 const myReqLogger =
require('./Utilities/requestLogger');
 const route = require('./Routes/routing');
 const app = express();
 app.use(bodyparser.json());
 app.use(myReqLogger);
 app.use('/', route);
 const port = process.env.PORT || 3000;
 app.listen(port, () => { console.log(`App running on
port ${port}...`);
 });
API Routes
 In the Routes folder, create a file with the name
"routing.js".
 This file contains route definitions for all the APIs of
the application.
 const express = require('express');
 const routing = express.Router();
 const notesController =
require('../Controller/myNotes');
 routing.get('/notes', notesController.getNotes);
 routing.post('/notes', notesController.newNotes);
 routing.put('/notes/:id',
notesController.updateNotes);
 routing.delete('/notes/:id',
notesController.deleteNotes);
 routing.all('*',
notesController.invalid); module.exports = routing;
Model
 In the Model folder, create a file with the name
"myNotesSchema.js".
 Logic to connect to MongoDB using mongoose, schema, and the
model creation logic will be included in this file.
 const mongoose = require('mongoose');
 mongoose .connect('mongodb://localhost:27017/IntellectNotes',
 { useNewUrlParser: true, useCreateIndex: true,
useFindAndModify: false, useUnifiedTopology: true, })
 .then(() => console.log('DB connection successful!'));
 //Schema
 const myNotesSchema = new mongoose.Schema(
 { notesID: { type: Number, unique: true, required: [true,
'Required field'], },
 name: { type: String, required: [true, 'Required field'], },
data: { type: String, },
 },
 { timestamps: { createdAt: true, updatedAt:
true, }, }); //Model
 const NotesModel = mongoose.model('mynotes', myNotesSchema);
 module.exports = NotesModel;
Controllers
 In the Controller folder, create a file with the name
"myNotes.js".
 This file contains business logic for all the APIs of the application.
 Custom validators will be imported and accessed based on the
requirement.
 All the controllers will send the response back to the client based
on the request received. Error handling also is taken care of
accordingly.
 const NotesModel = require('../Model/myNotesSchema');
 const validators = require('../Utilities/validator');
 exports.getNotes = async (req, res) => {
 try { const notes = await NotesModel.find({}, { _id: 0, __v:
0 });
 if (notes.length > 0) {
 res.status(200).json({ status: 'success', results:
notes.length, data: { notes, },
 }); }
 else { res.status(400).json({ status: 'success', data:
{ message: 'No notes available in the repo', },
 }); } }
 catch (err) {
 res.status(404).json({ status: 'fail', message:
err, }); }};
 exports.newNotes = async (req, res) => {
 try {
 if (validators.ValidateName(req.body.name)) {
 const newNotes = await NotesModel.create(req.body);
res.status(201).json({ status: 'success',
data: { newNotes, },
 }); }
 else { res.status(400).json({ status: 'error',
results: 'Enter valid name', }); } } catch (err) {
res.status(404).json({ status: 'fail', message:
err.errmsg, }); }}; exports.updateNotes = async
(req, res) => { try { const notes = await
NotesModel.findOneAndUpdate( { notesID:
req.params.id }, req.body, { new: true, //to
return new doc back runValidators: true, //to run
the validators which specified in the model } );
 if (notes != null)
{ res.status(200).json({ status: 'success',
data: { notes, }, }); } else {
res.status(400).json({ status: 'success',
data: { message: `No notes available with
ID ${req.params.id} `, }, }); } } catch
(err) { res.status(404).json({ status: 'fail',
message: err, }); }}; exports.deleteNotes =
async (req, res) => { const delDet = await
NotesModel.deleteOne({ notesID:
req.params.id }); if (delDet.deletedCount === 0)
{ res.status(404).json({ status: 'fail',
message: 'No notes available for this ID', }); }
else { res.status(200).json({ status:
'success', message: `Notes with $
{req.params.id} ID
deleted`, }); }}; exports.invalid = async (req,
res) => { res.status(404).json({ status: 'fail',
message: 'Invalid path', });};
Utilities
 In the application, we will need specific helper files.
For instance, we need to have a logger that should
keep track of all the requests that comes into the
application or some custom validators which we can
make use in the controller.
 Inside the Utilities folder create the following files
with the content.
 requestLogger.js
 const fs = require('fs');const { promisify } =
require('util'); const appendFile =
promisify(fs.appendFile); async function
requestLogger(req, res, next) { try { const
logMessage = `${new Date()} - ${req.method} - $
{req.url} \n`; await
appendFile('RequestLogger.log', logMessage);
next(); } catch (err)
{ next(err); }} module.exports = requestLogger;
validator.js
exports.ValidateName = function
(name) { if (name.trim().length >
0) { return true; } return
false;};
Project flow
The following figure visually
explains the application data flow.
Project Execution
 API –1
 URL – http://localhost:3000/notes
 Method - GET
 Description – API to fetch all the notes.
 API –2
 URL – http://localhost:3000/notes
 Method - POST
 Description – API to add new notes.
 API –3
 URL – http://localhost:3000/notes/7558
 Method - PUT
 Description – API to update existing notes.
 API –4
 URL – http://localhost:3000/notes/7558
 Method - DELETE
 Description – API to delete existing notes.
 API –5
 URL – http://localhost:3000/mynotes
 Method - ALL
 Description – default API to handle invalid
routes.
Why Session management?
 Every user interaction with an application is an
individual request and response. The need to
persist information between requests is
important for maintaining the ultimate
experience for the user for any web application.
 Session management is useful in the scenarios
mentioned below:
 We need to maintain that a user has already
been authenticated with the application.
 To retain various personalized user information
that is associated with a session.

 Let us now understand how we can set up
sessions securely in our application to lessen
risks like session hijacking.
 Session Management is a technique used
by the webserver to store a particular
user's session information. The Express
framework provides a consistent interface
to work with the session-related data. The
framework provides two ways of
implementing sessions:
 By using cookies
 By using the session store
Introduction to cookies
Cookies are a piece of information
sent from a website server and
stored in the user's web browser
when the user browses that
website. Every time the user loads
that website back, the browser
sends that stored data back to the
website server, to recognize the
user.
Configuration
 The Express framework provides a cookie
API using cookieParser middleware.
The middleware cookieParser parses the
cookies which are attached to the request
object.
 To install the cookieParser middleware, issue the
below command in the Node command prompt.
npm install cookie-parser
 The above middleware can be configured in
Express application as shown below:
 const express = require('express');
 const cookieParser = require('cookie-parser');
 const app = express();
 app.use(cookieParser());
 The cookie-parser middleware is imported and
then associated with the application object using
Setting and reading cookies
Setting cookies:
routing.get('/user/:name',

notesController.user1);
exports.user1 = async (req, res)
=> {
 res.cookie('name',
req.params.name);
 res.send('<p>Cookie set:<a
href="/user"> View here </a>');
};
 When the user navigates to URL "
/user/<username>", the cookie is set with
the name username and the value is
retrieved using the params property of
the request object. Thus for setting
cookies, the general syntax is as shown
below:
 res.cookie('cookieName', value, { expires:
new Date(), maxAge: 99999 });
 The arguments of the above method are
 the name of the cookie
 cookie value
 the options to be used while configuring
cookie, an optional object.
Some of the options that can be
specified while configuring a
cookie are shown below:
Reading cookies:
To access a particular cookie,
use the cookies property of
the request object.
exports.user2 = async (req, res) =>
{
res.send(req.cookies.name);
};
Whenever the user visits the "/user"
route, the value of the cookie is
fetched
using request.cookies property and
displayed to the user.
Updating and deleting cookies

 Updating cookies:
 A cookie can be updated by re-creating it with
new properties. For example, if we need to
update a cookie named username:
 res.cookie('username', new_value)
 Deleting cookies:
 It is possible to remove a cookie with
the response object's clearCookie() method.
This method accepts the name of the cookie
which we want to delete.
 app.get('/user', myController.myMethod);
 exports.myMethod = async (req, res) => {
 res.clearCookie('username');
res.send(req.cookies.username);
 };
Types of cookies
 Session cookies
 The cookies which exist for a
browser session are defined as Session
cookies and they are rejected whenever
the browser is closed.
 While configuring a cookie, if the 'expires'
option is not specified with any value,
then a session cookie is created by
default.
 res.cookie('name', 'John')

A session cookie is also created on setting


value as "0" for the "expires" option.
 res.cookie('name', 'John', { expires: 0 })
 Signed cookies
 The cookies which have a signature attached to
its value are considered as Signed cookies. To
generate this signature, any secret string value
can be used while adding the cookie
middleware into the application object.
 A signed cookie can be created as shown below,
by passing a string value while instantiating it:
 app.use(cookieParser('S3CRE7'))
 To access the signed cookies, use the property
called signedCookies of the request object.
For example, if we need to access the value of
a signed cookie:
 request.signedCookies.username
 Session cookies are deleted on closing the
browser. The other cookies are deleted on
reaching the expiry date.
Demo of Using Cookies:
 Highlights:
 Session management
 Use of Cookies
 Download the source code for the demo here
.
 Demo steps:
 1. Modify the app.js file in TestApp as shown
below:
 const express = require('express');const
cookieParser = require('cookie-parser');const
router = require('./Routes/routing'); const app
=
express();app.use(cookieParser());app.use('/',
router);app.listen(3000);
 console.log('Server listening in port 3000');
2. Modify the routing.js file in
TestApp as shown below:
const express = require('express');
const myController =
require('../Controller/myController')
;
const router = express.Router();
router.get('/user/:name',
myController.user1);
router.get('/user',
myController.user2);
module.exports = router;
3. In Controller, add the below
code:
exports.user1 = async (req, res)
=> { res.cookie('name',
req.params.name);
res.send('<p>Cookie set:<a
href="/user"> View here </a>');
};
4. Save the files. Start the server.

Access the URL


"http://localhost:3000/user/<usern
ame>" and observe the output.
5. Open the developer tools in the
browser window and click on the
Console tab and
type document.cookie and verify
the value displayed.
6. On click of the "View here" link,
the cookie is retrieved and displayed
as below:

7. Open the developer tools in the


browser window and click on the
Console tab and
type document.cookie and verify
the value displayed.
Sessions
 Session store for session management
 A session store can be used to store
the session data in the back-end. Using this
approach, a large amount of data can be
stored, and also the data will be hidden
from the user, unlike a cookie.
 Configuration
 Express provides a
middleware called express-session for
storing session data on the server-side.
 To install express-session middleware,
use npm.
npm install express-session
 To use this module in the Express
application, first, import it as shown below:
 const session = require('express-session');
 Then the session is to be initialized as follows:
 app.use(session());

 The session middleware also accepts an object


'options' for defining different configuration
options.
 app.use(session({
 secret: 'keyboard',
 resave: false,
 saveUninitialized: true,
 cookie: { secure: true }
 })
 );
 secret - used for signing
 resave - a boolean value which makes
the session to be saved when not modified as
well
 saveUninitialized - a boolean value which
makes the session which is uninitialized to be
saved to the store
 cookie - configurations for a session cookie
 The built-in session store called MemoryStore
is used in Express by default. But it is not
suggested for use in a production
environment due to memory leakage.
 Express also supports the usage of any third-
party module like RedisStore which stores
session data in Redis, which is an in-memory
data store.
Session Variables

Session variables are the variables that are


associated with a user's session.
Consider the example code below which
uses a session variable
called page_views.
exports.myMethod = async (request,
response) => { if (request.session.views)
{ request.session.views++;
response.send(`You visited this page $
{request.session.views} times`); } else {
request.session.views = 1;
response.send('Welcome to this page for
the first time!'); }};
 According to the above code snippet, a session variable
called views is created when the user visits the
website. The session variable is updated accordingly,
whenever the user comes next time.
 The session variables are set independently for each
user and it can be accessed using the session property
of the request object as shown below:
 request.session

 Setting session variables
 A session variable can be set by attaching it to the
request object either using the dot notation or the
substring syntax.
 request.session.username =
'John';request.session['username'] = 'John';
Reading session variables
To read a session variable, use the request
object as shown below:
const username =
request.session.usernameconst username =
request.session['username']

Updating session variables
A session variable can be updated using the
req.session object or use a new value to
overwrite the existing one.
request.session.username.push('value');request
.session.username = 'John';
Demo- Using Session store
 Highlights:
 Sessionmanagement
 Usage of the Session store
 Download the source code for the demo here.

 Demo steps:
 1. Open the TestApp folder in the command prompt
and run the command "npm install" for installing the
dependencies mentioned in the package.json file.
 2. In the file server-session.js, use the below code:
 const express = require('express'); const app =
express();const session = require('express-
session'); app.use( session({ name: 'my-session',
cookie: {
//Current Server time + maxAge
= expire datetime maxAge:
1000 * 60, //Allows for the
cookie to be read only by a
server (no JS) httpOnly: true,
//Set for the root of the domain.
path: '/', }, secret:
'mypasswordinfy', })); app.use((r
eq, res, next) => { let { visit } =
req.session;
if (!visit) { visit =
req.session.visit = { count: 1,
}; } else { visit.count++; }
next();}); app.get('/', (req, res)
=> { res.send(`you viewed this
page ${req.session.visit.count}
times`);}); app.listen(3000);cons
ole.log('Server started...running
with port 3000');
2. Start the Server.

3. Observe the below output:


Securing Express
applications
Why Security?
Attackers may attempt to exploit
security vulnerabilities present in web
applications in various ways. They may
plan attacks like clickjacking, cross-site
scripting, placing insecure requests and
identifying web application frameworks
etc.
It is important to follow secure coding
techniques for developing secure,
robust and hack-resilient applications.
 What is Security?
 Security is basically about protecting the application
assets like the web page, the database, and so on.
 Security depends on the following elements:
 Authentication: the process of exclusively identifying the
clients of your applications and services.
 Authorization: a process that manages the resources and
operations that the authenticated user is permitted to access.
 Auditing: process to assure that a user cannot deny
performing an operation or initiating a transaction.
 Confidentiality: the process of making sure that data
remains private and confidential.
 Integrity: the promise that data is protected from malicious
modification.
 Availability: means that systems remain available for
legitimate users.
Use of Helmet Middleware
Express applications can be secured by
using a middleware called helmet.
The helmet middleware is a set of 14
small middleware functions that help in
setting up security-related HTTP headers
with default values and also
removes unnecessary headers which
expose the application related
information.
Below are the set of middleware functions
that helmet provides to protect an
Express application:
Best Practices
Tip: Use Helmet if you’re writing
a web app
If you’re writing a web
application, there are a lot of
common best practices that you
should follow to secure your
Helmet configuration
 Toinstall helmet in any Express application, use
node package manager and run the below
command.
 npm install helmet

 Once helmet is installed, it is to be associated with
the Express application object.
 var helmet = require('helmet');app.use(helmet());

 Express also provides the option of enabling pieces
of helmet middleware individually as shown below.
 app.use(helmet.noCache());app.use(helmet.frameg
uard());
Italso provides the functionality of
disabling a middleware that's normally
enabled by default based on the
application requirement.
For example, frameguard middleware
mitigates clickjacking attacks by
setting a header 'X-Frame-Options'. For
disabling this middleware in the helmet
stack, modify the code as shown below.
app.use(helmet({ frameguard:
false}));
Benefit of using Helmet
Middleware
Consider an Express application
server code that does not have
helmet middleware added.
Once the server is started and
when the client sends a request
to the server, have a look at the
headers generated as part of the
response.
 When any request is sent to the server from a
client, the server will process the request and
sends the response back to the client without
any protections that the helmet middleware
could have possibly provided, if it was used.
 In the above response headers, we can see a
header "X-Powered-By" with the value as
"Express". From this, we can understand that
the application is running on an Express
server. We can also see that there are no
clickjacking protections available and no
cache control headers are set for the
application.
Now if the helmet middleware
was used, here's what the
response headers would look like:
 We can see that some extra headers get set.
 The X-Content-Type-Options header is set to value nosniff.
This does not allow the browser to guess the MIME type of a
file.
 The X-Download-Options header is set to value noopen.
This disables the option to open a file directly on download.
 The X-Frame-Options header is set to value SAMEORIGIN.
This is used to indicate whether a browser should be allowed
to render a page within a <frame> or <iframe>, but only from
the originating host.
 The X-XSS-Protection header is set to value 1;
mode=block. This instructs Internet Explorer to enable the
anti-cross-site scripting filter.
 The X-Powered-By header is removed so that the attackers
cannot see which server is used for running the application.
Thank You

You might also like