Full Stack-Unit-Iii

You might also like

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 56

UNIT- III

INTRODUCTION NoSQL Nosql,known as Not only sql


database.
NoSQL Database is a non-relational Data Management System, that does not require a
fixed schema. It avoids joins, and is easy to scale. The major purpose of using a NoSQL
database is for distributed data stores with humongous data storage needs. NoSQL is
used for Big data and real-time web apps. For example, companies like Twitter,
Facebook and Google collect terabytes of user data every single day.
NoSQL database stands for “Not Only SQL” or “Not SQL.” Though a better term would
be “NoREL”, NoSQL caught on. Carl Strozz introduced the NoSQL concept in 1998.

Traditional RDBMS uses SQL syntax to store and retrieve data for further insights.
Instead, a NoSQL database system encompasses a wide range of database
technologies that can store structured, semi-structured, unstructured and polymorphic
data. Let’s understand about NoSQL with a diagram in this NoSQL database tutorial:

In this NoSQL tutorial for beginners, you will learn NoSQL basics like:

 What is NoSQL?
 Why NoSQL?
 Brief History of NoSQL Databases
 Features of NoSQL
 Types of NoSQL Databases
 Query Mechanism tools for NoSQL
 What is the CAP Theorem?
 Eventual Consistency
 Advantages of NoSQL
 Disadvantages of NoSQL

Why NoSQL?
The concept of NoSQL databases became popular with Internet giants like Google,
Facebook, Amazon, etc. who deal with huge volumes of data. The system response time
becomes slow when you use RDBMS for massive volumes of data.

To resolve this problem, we could “scale up” our systems by upgrading our existing
hardware. This process is expensive.
The alternative for this issue is to distribute database load on multiple hosts whenever
the load increases. This method is known as “scaling out.”

NoSQL database is non-relational, so it scales out better than relational databases as


they are designed with web applications in mind.

Brief History of NoSQL Databases


 1998- Carlo Strozzi use the term NoSQL for his lightweight, open-source
relational database
 2000- Graph database Neo4j is launched
 2004- Google BigTable is launched
 2005- CouchDB is launched
 2007- The research paper on Amazon Dynamo is released
 2008- Facebooks open sources the Cassandra project
 2009- The term NoSQL was reintroduced

Features of NoSQL
Non-relational

 NoSQL databases never follow the relational model


 Never provide tables with flat fixed-column records
 Work with self-contained aggregates or BLOBs(Binary Large Objects)
 Doesn’t require object-relational mapping and data normalization
 No complex features like query languages, query planners, referential integrity
joins, ACID

Schema-free

 NoSQL databases are either schema-free or have relaxed schemas


 Do not require any sort of definition of the schema of the data
 Offers heterogeneous structures of data in the same domain

NoSQL is Schema-Free
Simple API

 Offers easy to use interfaces for storage and querying data provided
 APIs allow low-level data manipulation & selection methods
 Text-based protocols mostly used with HTTP REST with JSON
 Mostly used no standard based NoSQL query language
 Web-enabled databases running as internet-facing services

Distributed

 Multiple NoSQL databases can be executed in a distributed fashion


 Offers auto-scaling and fail-over capabilities
 Often ACID concept can be sacrificed for scalability and throughput
 Mostly no synchronous replication between distributed nodes Asynchronous
Multi-Master Replication, peer-to-peer, HDFS Replication
 Only providing eventual consistency
 Shared Nothing Architecture. This enables less coordination and higher
distribution.

NoSQL is Shared Nothing.

Types of NoSQL Databases


NoSQL Databases are mainly categorized into four types: Key-value pair, Column-
oriented, Graph-based and Document-oriented. Every category has its unique attributes
and limitations. None of the above-specified database is better to solve all the problems.
Users should select the database based on their product needs.
Types of NoSQL Databases:

 Key-value Pair Based


 Column-oriented Graph
 Graphs based
 Document-oriented
Key Value Pair Based
Data is stored in key/value pairs. It is designed in such a way to handle lots of data and
heavy load.

Key-value pair storage databases store data as a hash table where each key is unique,
and the value can be a JSON, BLOB(Binary Large Objects), string, etc.

For example, a key-value pair may contain a key like “Website” associated with a value
like “Guru99”.

It is one of the most basic NoSQL database example. This kind of NoSQL database is
used as a collection, dictionaries, associative arrays, etc. Key value stores help the
developer to store schema-less data. They work best for shopping cart contents.

Redis, Dynamo, Riak are some NoSQL examples of key-value store DataBases. They
are all based on Amazon’s Dynamo paper.

Column-based
Column-oriented databases work on columns and are based on BigTable paper by
Google. Every column is treated separately. Values of single column databases are
stored contiguously.

Column based NoSQL database

They deliver high performance on aggregation queries like SUM, COUNT, AVG, MIN
etc. as the data is readily available in a column.

Column-based NoSQL databases are widely used to manage data


warehouses, business intelligence, CRM, Library card catalogs,

HBase, Cassandra, HBase, Hypertable are NoSQL query examples of column based
database.

Document-Oriented:
Document-Oriented NoSQL DB stores and retrieves data as a key value pair but the
value part is stored as a document. The document is stored in JSON or XML formats.
The value is understood by the DB and can be queried.
Relational Vs. Document

In this diagram on your left you can see we have rows and columns, and in the right, we
have a document database which has a similar structure to JSON. Now for the relational
database, you have to know what columns you have and so on. However, for a
document database, you have data store like JSON object. You do not require to define
which make it flexible.

The document type is mostly used for CMS systems, blogging platforms, real-time
analytics & e-commerce applications. It should not use for complex transactions which
require multiple operations or queries against varying aggregate structures.

Amazon SimpleDB, CouchDB, MongoDB, Riak, Lotus Notes, MongoDB, are popular
Document originated DBMS systems.

Graph-Based
A graph type database stores entities as well the relations amongst those entities. The
entity is stored as a node with the relationship as edges. An edge gives a relationship
between nodes. Every node and edge has a unique identifier.

OVERVIEW OF MONGO DB

Like any other database management language, MongoDB is based on a NoSQL database
that is used for storing data in a key-value pair. Its working is based on the concept of
document and collection. It is also an open-source, a document-oriented, cross-platform
database system that is written using C++. In this chapter, you will learn more about
MongoDB and its importance.
Mongo DB can be defined as a document-oriented database system that uses the concept of
NoSQL. It also provides high availability, high performance, along with automatic scaling.
This open-source product was developed by the company - 10gen in October 2007, and the
company also maintains it. MongoDB exists under the General Public License (GPL) as a
free database management tool as well as available under Commercial license as of the
manufacturer. MongoDB was also intended to function with commodity servers. Companies
of different sizes all over the world across all industries are using MongoDB as their
database.

Here are some key terminologies that you must know to get into the in-depth of MongoDB:

What is a Database?
In MongoDB, a database can be defined as a physical container for collections of data. Here,
on the file system, every database has its collection of files residing. Usually, a MongoDB
server contains numerous databases.

What are Collections?


Collections can be defined as a cluster of MongoDB documents that exist within a single
database. You can relate this to that of a table in a relational database management system.
MongoDB collections do not implement the concept of schema. Documents that have
collection usually contain different fields. Typically, all the documents residing within a
collection are meant for a comparable or related purpose.

What is a Document?
A document can be defined as a collection of key-value pairs that contain dynamic schema.
Dynamic schema is something that documents of the equal collection do not require for
having the same collection of fields or construction, and a common field is capable of holding
various types of data.

Here is a table showing the relation between the terminologies used in RDBMS and MongoDB:

RDBMS MongoDB

Database Database

Table Collection

Tuple or Row Document

Column Field

Table Join Embedded Documents

Primary Key Primary key / Default key

Mysqld / Oracle mongod

Popular Organizations That Use MongoDB


Here is a list of some popular and multinational companies and organizations that are using
MongoDB as their official database to perform and manage different business applications.

 Adobe
 McAfee
 LinkedIn
 FourSquare
 MetLife
 eBay
 SAP

Where Is MongoDB Used?


Beginners need to know the purpose and requirement of why to use MongoDB or what is the
need of it in contrast to SQL and other database systems. In simple words, it can be said that
every modern-day application involves the concept of big data, analyzing different forms of
data, fast features improvement in handling data, deployment flexibility, which old database
systems are not competent enough to handle. Hence, MongoDB is the next choice.

Why Use MongoDB?


Some basic requirements are supported by this NoSQL database, which is lacking in other
database systems. These collective reasons make MongoDB popular among other database
systems:

 Document-Oriented data storage, i.e., data, is stored in a JSON style format, which increases
the readability of data as well.
 Replication and high availability of data.
 MongoDB provides Auto-sharding.
 Ad hoc queries are supported by MongoDB, which helps in searching by range queries, field,
or using regex terms.
 Indexing of values can be used to create and improve the overall search performance in
MongoDB. MongoDB allows any field to be indexed within a document.
 MongoDB has a rich collection of queries.
 Updating of data can be done at a faster pace.
 It can be integrated with other popular programming languages also to handle structured as
well as unstructured data within various types of applications.

Advantages of Using MongoDB

 It is easy to set up, i.e., install the MongoDB.


 Since MongoDB is a schema-less database, so there is no hassle of schema migration.
 Since it is a document-oriented language, document queries are used, which plays a vital
role in supporting dynamic queries.
 Easily scalable.
 It is easy to have a performance tuning as compared to other relational databases.
 It helps in providing fast accessing of data because of its nature of implementing the internal
memory to store the data.
 MongoDB is also used as a file system that can help in easy management of load balancing.
 MongoDB also supports the searching using the concept of regex (regular expression) as well
as fields.
 Users can run MongoDB as a windows service also.
 It does not require any VM to run on different platforms.
 It also supports sharding of data.

MONGO DB QUERY DOCUMENTS

➤ Use the Select your language drop-down menu in the


upper-right to set the language of the following examples.
This page provides examples of query operations using
the db.collection.find() method in mongosh . The examples on
this page use the inventory collection. To populate
the inventory collection, run the following:

db.inventory.insertMany([

{ item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },

{ item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" },

{ item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },

{ item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },

{ item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" }

]);

MongoDB Shell

You can run the operation in the web shell below:

Select All Documents in a Collection


To select all documents in the collection, pass an empty document as the query filter
parameter to the find method. The query filter parameter determines the select criteria:

db.inventory.find( {} )

MongoDB Shell

This operation corresponds to the following SQL statement:

SELECT * FROM inventory

For more information on the syntax of the method, see find() .

Specify Equality Condition


To specify equality conditions, use <field>:<value> expressions in the query filter
document:

{ <field1>: <value1>, ... }


MongoDB Shell

The following example selects from the inventory collection all documents where
the status equals "D" :

db.inventory.find( { status: "D" } )

MongoDB Shell

This operation corresponds to the following SQL statement:

SELECT * FROM inventory WHERE status = "D"

NOTE

The MongoDB Compass query bar autocompletes the current query based on the
keys in your collection's documents, including keys in embedded sub-documents.

Specify Conditions Using Query

Operators
A query filter document can use the query operators to specify conditions in the following
form:

{ <field1>: { <operator1>: <value1> }, ... }

MongoDB Shell

The following example retrieves all documents from the inventory collection
where status equals either "A" or "D" :

db.inventory.find( { status: { $in: [ "A", "D" ] } } )

MongoDB Shell

NOTE

Although you can express this query using the $or operator, use the $in operator
rather than the $or operator when performing equality checks on the same field.

The operation corresponds to the following SQL statement:

SELECT * FROM inventory WHERE status in ("A", "D")


Refer to the Query and Projection Operators document for the complete list of MongoDB
query operators.

Specify AND Conditions


A compound query can specify conditions for more than one field in the collection's
documents. Implicitly, a logical AND conjunction connects the clauses of a compound query
so that the query selects the documents in the collection that match all the conditions.

The following example retrieves all documents in the inventory collection where
the status equals "A" and qty is less than ( $lt ) 30 :

db.inventory.find( { status: "A", qty: { $lt: 30 } } )

MongoDB Shell

The operation corresponds to the following SQL statement:

SELECT * FROM inventory WHERE status = "A" AND qty < 30

See comparison operators for other MongoDB comparison operators.

Specify OR Conditions
Using the $or operator, you can specify a compound query that joins each clause with a
logical OR conjunction so that the query selects the documents in the collection that match at
least one condition.

The following example retrieves all documents in the collection where


the status equals "A" or qty is less than ( $lt ) 30 :

db.inventory.find( { $or: [ { status: "A" }, { qty: { $lt: 30 } } ] } )

MongoDB Shell

The operation corresponds to the following SQL statement:

SELECT * FROM inventory WHERE status = "A" OR qty < 30

NOTE

Queries which use comparison operators are subject to Type Bracketing.


Specify AND as well as OR Conditions

In the following example, the compound query document selects all documents in the
collection where the status equals "A" and either qty is less than ( $lt ) 30 or item starts
with the character p :

db.inventory.find( {

status: "A",

$or: [ { qty: { $lt: 30 } }, { item: /^p/ } ]

})

MongoDB Shell

The operation corresponds to the following SQL statement:

SELECT * FROM inventory WHERE status = "A" AND ( qty < 30 OR item LIKE "p%")

NOTE

MongoDB supports regular expressions $regex queries to perform string pattern


matches.

Getting the Request Body in Express

Express doesn't automatically parse the HTTP request body for


you, but it does have an officially supported middleware package
for parsing HTTP request bodies. As of v4.16.0, Express comes
with a built-in JSON request body parsing middleware that's good
enough for most JavaScript apps.

JSON Request Body


Express has a built-in express.json() function that returns
an Express middleware function that parses JSON HTTP request
bodies into JavaScript objects. The json() middleware adds
a body property to the Express request req. To access the parsed
request body, use req.body as shown below.

const express = require('express');


const app = express();

// Parse JSON bodies for this app. Make sure you put
// `app.use(express.json())` **before** your route handlers!
app.use(express.json());

app.post('*', (req, res) => {


req.body; // JavaScript object containing the parse JSON
res.json(req.body);
});
const server = await app.listen(3000);

// Demo showing the server in action


const axios = require('axios');
const res = await axios.post('http://localhost:3000/', {
answer: 42
});
res.data; // `{ answer: 42 }`

Common Gotchas
If the JSON body is malformed, Express will error out with an
HTTP 400. This error also triggers error handling middleware.

const express = require('express');


const app = express();
app.use(express.json());
app.post('*', (req, res) => {
res.json(req.body);
});

// Add error handling middleware that Express will call


// in the event of malformed JSON.
app.use(function(err, req, res, next) {
// 'SyntaxError: Unexpected token n in JSON at position 0'
err.message;
next(err);
});
const server = await app.listen(3000);

// Demonstrate the server in action


const axios = require('axios');
const headers = { 'Content-Type': 'application/json' };
const err = await axios.
post('http://localhost:3000/', 'not json', { headers }).
then(() => null, err => err);

// Express will send an HTTP 400 by default if JSON middleware


// failed to parse.
err.response.status; // 400
err.message; // 'Request failed with status code 400'

It is important to note that, by default, the json() middleware


ignores any request whose Content-Type header isn't something that
Express recognizes as JSON. If express.json() is silently ignoring
your request, make sure you check the Content-Type header.

const express = require('express');


const app = express();
app.use(express.json());
app.post('*', (req, res) => {
// undefined, body parser ignored this request
// because of the content-type header
req.body;
res.json(req.body);
});
const server = await app.listen(3000);

// Demo of making a request the JSON body parser ignores.


const axios = require('axios');
const headers = { 'Content-Type': 'text/plain' };
const res = await axios.
post('http://localhost:3000/', 'not json', { headers });

res.data; // Empty object `{}`

URL-Encoded Form Body Parser


Express has an officially supported module body-parser that
includes a parser for URL-encoded request bodies, like the ones
submitted by HTML forms.

const express = require('express');


const app = express();
app.use(require('body-parser').urlencoded({ extended: false }));
app.post('*', (req, res) => {
req.body; // { answer: 42 }
res.json(req.body);
});
const server = await app.listen(3000);

// Demo of making a request with a URL-encoded body.


const axios = require('axios');
const headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
const res = await axios.
post('http://localhost:3000/', 'answer=42', { headers });

res.data; // { answer: 42 }

Files
Neither Express nor body-parser supports file uploads out of the
box. However, you can use the Formidable module on npm to
handle file uploads. You can learn how on our tutorial on file
uploads with Express.

Want to become your team's Express expert? There's no better


way to really grok a framework than to write your own clone from
scratch. In 15 concise pages, this tutorial walks you through how
to write a simplified clone of Express called Espresso. Get your
copy!

Espresso supports:

 Route handlers, like `app.get()` and `app.post()`


 Express-compatible middleware, like
`app.use(require('cors')())`
 Express 4.0 style subrouters

As a bonus, Espresso also supports async functions, unlike


Express.

NODEJS MONGODB CONNECTION

Use Node.js? Want to learn MongoDB? This is the blog series for you!

In this Quick Start series, I’ll walk you through the basics of how to get
started using MongoDB with Node.js. In today’s post, we’ll work
through connecting to a MongoDB database from a Node.js script,
retrieving a list of databases, and printing the results to your console.

Prefer to learn by video? I've got ya covered. Check out the video
below that covers how to get connected as well as how to perform the
CRUD operations.

Set up
Before we begin, we need to ensure you’ve completed a few
prerequisite steps.

Install Node.js
First, make sure you have a supported version of Node.js installed. The
current version of MongoDB Node.js Driver requires Node 4.x or
greater. For these examples, I've used Node.js 14.15.4. See
the MongoDB Compatability docs for more information on which
version of Node.js is required for each version of the Node.js driver.

Install the MongoDB Node.js Driver


The MongoDB Node.js Driver allows you to easily interact with
MongoDB databases from within Node.js applications. You'll need the
driver in order to connect to your database and execute the queries
described in this Quick Start series.
If you don't have the MongoDB Node.js Driver installed, you can install
it with the following command.
npm install mongodb

At the time of writing, this installed version 3.6.4 of the driver.


Running npm list mongodb will display the currently installed driver
version number. For more details on the driver and installation, see
the official documentation.

Create a free MongoDB Atlas cluster and load the


sample data
Next, you'll need a MongoDB database. The easiest way to get started
with MongoDB is to use Atlas, MongoDB's fully-managed database-as-a-
service.

Head over to Atlas and create a new cluster in the free tier. At a high
level, a cluster is a set of nodes where copies of your database will be
stored. Once your tier is created, load the sample data. If you're not
familiar with how to create a new cluster and load the sample data,
check out this video tutorial from MongoDB Developer
Advocate Maxime Beugnet.

Get started with an M0 cluster on Atlas today. It's free forever, and
it's the easiest way to try out the steps in this blog series.

Get your cluster’s connection info


The final step is to prep your cluster for connection.

In Atlas, navigate to your cluster and click CONNECT. The Cluster


Connection Wizard will appear.

The Wizard will prompt you to add your current IP address to the IP
Access List and create a MongoDB user if you haven't already done so.
Be sure to note the username and password you use for the new
MongoDB user as you'll need them in a later step.

Next, the Wizard will prompt you to choose a connection method.


Select Connect Your Application. When the Wizard prompts you to
select your driver version, select Node.js and 3.6 or later. Copy the
provided connection string.

For more details on how to access the Connection Wizard and


complete the steps described above, see the official documentation.
Connect to your database from a Node.js
application
Now that everything is set up, it’s time to code! Let’s write a Node.js
script that connects to your database and lists the databases in your
cluster.

Import MongoClient
The MongoDB module exports MongoClient, and that’s what we’ll use to
connect to a MongoDB database. We can use an instance of
MongoClient to connect to a cluster, access the database in that
cluster, and close the connection to that cluster.
const {MongoClient} = require('mongodb');

Create our main function


Let’s create an asynchronous function named main() where we will
connect to our MongoDB cluster, call functions that query our
database, and disconnect from our cluster.
async function main() {
// we'll add code here soon
}

The first thing we need to do inside of main() is create a constant for


our connection URI. The connection URI is the connection string you
copied in Atlas in the previous section. When you paste the connection
string, don't forget to update <username> and <password> to be the
credentials for the user you created in the previous section. The
connection string includes a <dbname> placeholder. For these examples,
we'll be using the sample_airbnb database, so
replace <dbname> with sample_airbnb.

Note: the username and password you provide in the connection string
are NOT the same as your Atlas credentials.
/**
* Connection URI. Update <username>, <password>, and <your-cluster-url> to
reflect your cluster.
* See https://docs.mongodb.com/ecosystem/drivers/node/ for more details
*/
const uri = "mongodb+srv://<username>:<password>@<your-cluster-url>/test?
retryWrites=true&w=majority";

Now that we have our URI, we can create an instance of MongoClient.


const client = new MongoClient(uri);
Note: When you run this code, you may see DeprecationWarnings
around the URL string parserand the Server Discover and Monitoring
engine. If you see these warnings, you can remove them by passing
options to the MongoClient. For example, you could instantiate
MongoClient by calling new MongoClient(uri, { useNewUrlParser: true,

useUnifiedTopology: true }). See the Node.js MongoDB Driver API


documentation for more information on these options.

Now we're ready to use MongoClient to connect to our


cluster. client.connect() will return a promise. We will use
the await keyword when we call client.connect() to indicate that we
should block further execution until that operation has completed.
await client.connect();

Now we are ready to interact with our database. Let's build a function
that prints the names of the databases in this cluster. It's often useful
to contain this logic in well named functions in order to improve the
readability of your codebase. Throughout this series, we'll create new
functions similar to the function we're creating here as we learn how
to write different types of queries. For now, let's call a function
named listDatabases().

await listDatabases(client);

Let’s wrap our calls to functions that interact with the database in
a try/catch statement so that we handle any unexpected errors.
try {
await client.connect();

await listDatabases(client);

} catch (e) {
console.error(e);
}

We want to be sure we close the connection to our cluster, so we’ll end


our try/catch with a finally statement.
finally {
await client.close();
}

Once we have our main() function written, we need to call it. Let’s send
the errors to the console.
main().catch(console.error);

Putting it all together, our main() function and our call to it will look
something like the following.
async function main(){
/**
* Connection URI. Update <username>, <password>, and <your-cluster-url>
to reflect your cluster.
* See https://docs.mongodb.com/ecosystem/drivers/node/ for more details
*/
const uri =
"mongodb+srv://<username>:<password>@<your-cluster-url>/test?
retryWrites=true&w=majority";

const client = new MongoClient(uri);

try {
// Connect to the MongoDB cluster
await client.connect();

// Make the appropriate DB calls


await listDatabases(client);

} catch (e) {
console.error(e);
} finally {
await client.close();
}
}

main().catch(console.error);

List the databases in our cluster


In the previous section, we referenced the listDatabases() function.
Let’s implement it!

This function will retrieve a list of databases in our cluster and print
the results in the console.
async function listDatabases(client){
databasesList = await client.db().admin().listDatabases();

console.log("Databases:");
databasesList.databases.forEach(db => console.log(` - ${db.name}`));
};

Save Your File


You’ve been implementing a lot of code. Save your changes, and name
your file something like connection.js. To see a copy of the complete file,
visit the nodejs-quickstart GitHub repo.

Execute Your Node.js Script


Now you’re ready to test your code! Execute your script by running a
command like the following in your terminal: node connection.js

You will see output like the following:


Databases:
- sample_airbnb
- sample_geospatial
- sample_mflix
- sample_supplies
- sample_training
- sample_weatherdata
- admin
- local

What’s next?
Today, you were able to connect to a MongoDB database from a
Node.js script, retrieve a list of databases in your cluster, and view the
results in your console. Nice!

Now that you're connected to your database, continue on to the next


post in this series where you'll learn to execute each of the CRUD
(create, read, update, and delete) operations.

In the meantime, check out the following resources:

 Official MongoDB Documentation on the MongoDB Node.js Driver


 MongoDB University Free Course: M220JS: MongoDB for
Javascript Developers

Questions? Comments? We'd love to connect with you. Join the


conversation on the MongoDB Community Forums.

How to Fetch Data From mongodb in Node js


and Display in HTML (ejs)
 Step 1 – Create Node Express js App
 Step 2 – Install express flash ejs body-parser mongoose
dependencies
 Step 3 – Connect App to MongoDB
 Step 4 – Create Model
 Step 5 – Create Routes
 Step 6 – Create HTML Table and Display List
 Step 7 – Import Modules in App.js
 Step 8 – Start App Server

Step 1 – Create Node Express js App

Execute the following command on terminal to create node js app:

mkdir my-app
cd my-app
npm init -y
Recommended:-Insert Data into MongoDB Using Node.js
Step 2 – Install express flash ejs body-parser mongoose Modules

Execute the following command on the terminal to express flash ejs


body-parser mysql dependencies :

npm install -g express-generator


npx express --view=ejs

npm install

npm install express-flash --save


npm install express-session --save
npm install body-parser --save
npm install mongoose

body-parser – Node.js request body parsing middleware which parses


the incoming request body before your handlers, and make it available
under req.body property. In other words, it simplifies the incoming
request.

Express-Flash – Flash Messages for your Express Application. Flash


is an extension of connect-flash with the ability to define a flash
message and render it without redirecting the request.

Express-Session– Express-session – an HTTP server-side framework


used to create and manage a session middleware.

Express-EJS– EJS is a simple templating language which is used to


generate HTML markup with plain JavaScript. It also helps to embed
JavaScript to HTML pages

Mongoose – Mongoose is a MongoDB object modeling tool designed


to work in an asynchronous environment. Mongoose supports both
promises and callbacks.

Recommended:-Node js Express MySQL User Authentication Rest API


Example

Step 3 – Connect App to MongoDB

Create database.js file into your app root directory and add the
following code into it to connect your app to the mongodb database:

1 var mongoose = require('mongoose');

2 mongoose.connect('mongodb://localhost:27017/test', {useNewUrlParser:
true});
3
var conn = mongoose.connection;
4 conn.on('connected', function() {

5 console.log('database is connected successfully');

6 });
7 conn.on('disconnected',function(){

8 console.log('database is disconnected successfully');

9 })

10 conn.on('error', console.error.bind(console, 'connection error:'));

module.exports = conn;
11

Recommended:-Insert Data into MongoDB Using Node.js

Step 4 – Create Model

Create Models directory and inside this directory create userModel.js


file; Then add following code into it:

1
const mongoose = require("../database");
2

3 // create an schema

4 var userSchema = new mongoose.Schema({

5 name: String,

6 email:String

7 });

8
var userModel=mongoose.model('users',userSchema);
9

10
module.exports = mongoose.model("Users", userModel);
11

Step 5 – Create Routes

Create routes; so visit routes directory and open users.js route file;
Then add the following routes into it:

1 var express = require('express');

2 var router = express.Router();

var mongoose = require('mongoose');


3
var userModel = require('../models/userModel');
4

6
/* GET home page. */
7
router.get('/', function(req, res, next) {
8

9
userModel.find((err, docs) => {
10
if (!err) {
11
res.render("list", {
12
data: docs
13
});
14 } else {

15 console.log('Failed to retrieve the Course List: ' +


err);
16
}
17
});
18

19
});
20 module.exports = router;

21

Step 6 – Create HTML Table and Display List

Create html form for display list from mongodb database; So


visit views directory and create list.ejs file inside it. Then add the
following code into it:

1 <!DOCTYPE html>

2 <html>
<head>
3
<title>fetch data from mongodb using node js and display in html</title>
4
<link rel='stylesheet' href='/stylesheets/style.css' />
5
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
6
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"
7
integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy"
8
crossorigin="anonymous"></script>
9 <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"

10 rel="stylesheet" integrity="sha384-MCw98/

11SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
12</head>

13<body>
<div>
14
<a href="/customers" class="btn btn-info ml-3">Fetch data from mongodb using node
15
</div>
16
<!-- <% if (messages.error) { %>
17
<p style="color:red"><%- messages.error %></p>
18
<% } %> -->
19

20<% if (messages.success) { %>

21 <p class="alert alert-success mt-4"><%- messages.success %></p>

22<% } %>

23<br>

24 <table class="table">

<thead>
25
<tr>
26
<th scope="col">#</th>
27
<th scope="col">Name</th>
28
<th scope="col">Email</th>
29

30
</tr>
31</thead>

32<tbody>

33 <% if(data.length){

34

35 for(var i = 0; i< data.length; i++) {%>

36 <tr>

<th scope="row"><%= (i+1) %></th>


37
<td><%= data[i].name%></td>
38
<td><%= data[i].email%></td>
39
</tr>
40
<% }
41
42

43 }else{ %>

<tr>
44
<td colspan="3">No user</td>
45
</tr>
46
<% } %>
47

48
</tbody>
49
</table>
50</body>

51</html>

Recommended:-Angular 12 CRUD + Node.js + Express + MySQL Tutorial

Step 5 – Import Modules in App.js

Import express flash session body-parser mongoose dependencies in


app.js; as shown below:

1 var createError = require('http-errors');

2 var express = require('express');

var path = require('path');


3
var cookieParser = require('cookie-parser');
4
var logger = require('morgan');
5
var bodyParser = require('body-parser');
6
var flash = require('express-flash');
7
var session = require('express-session');
8 var usersRouter = require('./routes/users');

9 var app = express();

10 // view engine setup

11 app.set('views', path.join(__dirname, 'views'));

12 app.set('view engine', 'ejs');

13 app.use(logger('dev'));

14 app.use(express.json());

15 app.use(express.urlencoded({ extended: false }));

app.use(cookieParser());
16
17 app.use(express.static(path.join(__dirname, 'public')));

18

19 app.use(session({

secret: '123456catr',
20
resave: false,
21
saveUninitialized: true,
22
cookie: { maxAge: 60000 }
23
}))
24

25
app.use(flash());
26 app.use('/list', usersRouter);

27

28 // catch 404 and forward to error handler

29 app.use(function(req, res, next) {

30 next(createError(404));

});
31

32
// error handler
33
app.use(function(err, req, res, next) {
34
// set locals, only providing error in development
35
res.locals.message = err.message;
36
res.locals.error = req.app.get('env') === 'development' ? err : {};
37

38 // render the error page

39 res.status(err.status || 500);

40 res.render('error');

41 });

42

43 // port must be set to 3000 because incoming http requests are routed from port 80
port 8080
44
app.listen(3000, function () {
45 console.log('Node app is running on port 3000');

46
47

48

49
module.exports = app;
50

51

Step 7 – Start App Server

You can use the following command to start node js app server:

//run the below command

npm start

after run this command open your browser and hit

http://127.0.0.1:3000/list

Conclusion
Fetch data from mongodb in node js express using mongoose express
app; In this tutorial, you have learned how to fetch and display data in
html list form mongoDB database using mongoose node js express app.

HANDLING COOKIES IN NODEJS

I want to be able to set a single cookie, and read that single cookie with each request made to the nodejs server
instance. Can it be done in a few lines of code, without the need to pull in a third party lib?

var http = require('http');

http.createServer(function (request, response) {


response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('Hello World\n');
}).listen(8124);

console.log('Server running at http://127.0.0.1:8124/');


Just trying to take the above code directly from nodejs.org, and work a cookie into it.

Cookies are small data that are stored on a client side and sent to the client along with
server requests. Cookies have various functionality, they can be used for maintaining
sessions and adding user-specific features in your web app. For this, we will use cookie-
parser module of npm which provides middleware for parsing of cookies.
First set your directory of the command prompt to root folder of the project and run the
following command:
npm init
This will ask you details about your app and finally will create a package.json file.
After that run the following command and it will install the required module and add them in
your package.json file
npm install express cookie-parser --save
package.json file looks like this :

After that we will setup basic express app by writing following code in our app.js file in root
directory .

let express = require('express');

//setup express app

let app = express()

//basic route for homepage

app.get('/', (req, res)=>{

res.send('welcome to express app');

});

//server listens to port 3000

app.listen(3000, (err)=>{

if(err)

throw err;

console.log('listening on port 3000');

});

After that if we run the command


node app.js
It will start our server on port 3000 and if go to the url: localhost:3000, we will get a page
showing the message :
welcome to express app
Here is screenshot of localhost:3000 page after starting the server :

So until now we have successfully set up our express app now let’s start with cookies.
For cookies first, we need to import the module in our app.js file and use it like other
middlewares.

var cookieParser = require('cookie-parser');


app.use(cookieParser());

Let’s say we have a user and we want to add that user data in the cookie then we have to
add that cookie to the response using the following code :
res.cookie(name_of_cookie, value_of_cookie);
This can be explained by the following example :

let express = require('express');

let cookieParser = require('cookie-parser');

//setup express app

let app = express()

app.use(cookieParser());

//basic route for homepage

app.get('/', (req, res)=>{

res.send('welcome to express app');

});

//JSON object to be added to cookie


let users = {

name : "Ritik",

Age : "18"

//Route for adding cookie

app.get('/setuser', (req, res)=>{

res.cookie("userData", users);

res.send('user data added to cookie');

});

//Iterate users data from cookie

app.get('/getuser', (req, res)=>{

//shows all the cookies

res.send(req.cookies);

});

//server listens to port 3000

app.listen(3000, (err)=>{

if(err)

throw err;

console.log('listening on port 3000');

});
So if we restart our server and make a get request to the route: localhost:3000/getuser
before setting the cookies it is as follows :

After making a request to localhost:3000/setuser it will add user data to cookie and gives
output as follows :

Now if we again make a request to localhost:3000/getuser as this route is iterating user


data from cookies using req.cookies so output will be as follows :

If we have multiple objects pushed in cookies then we can access specific cookie
using req.cookie.cookie_name .
Adding Cookie with expiration Time
We can add a cookie with some expiration time i.e. after that time cookies will be
destroyed automatically. For this, we need to pass an extra property to the res.cookie
object while setting the cookies.
It can be done by using any of the two ways :

//Expires after 400000 ms from the time it is set.


res.cookie(cookie_name, 'value', {expire: 400000 + Date.now()});
//It also expires after 400000 ms from the time it is set.
res.cookie(cookie_name, 'value', {maxAge: 360000});

Destroy the cookies :


We can destroy cookies using following code :
res.clearCookie(cookieName);
Now let us make a logout route which will destroy user data from the cookie. Now our
app.js looks like :

let express = require('express');

let cookieParser = require('cookie-parser');

//setup express app

let app = express()

app.use(cookieParser());

//basic route for homepage

app.get('/', (req, res)=>{

res.send('welcome to express app');

});

//JSON object to be added to cookie

let users = {

name : "Ritik",

Age : "18"

//Route for adding cookie


app.get('/setuser', (req, res)=>{

res.cookie("userData", users);

res.send('user data added to cookie');

});

//Iterate users data from cookie

app.get('/getuser', (req, res)=>{

//shows all the cookies

res.send(req.cookies);

});

//Route for destroying cookie

app.get('/logout', (req, res)=>{

//it will clear the userData cookie

res.clearCookie('userData');

res.send('user logout successfully');

});

//server listens to port 3000

app.listen(3000, (err)=>{

if(err)

throw err;

console.log('listening on port 3000');

});
HANDLING USER AUTHENTICATION WITH NODEJS

how to secure a Node.js web application built with the Express framework
by implementing user authentication. You'll enhance a starter Node.js
project to practice the following security concepts:

 Add user login and logout.


 Retrieve user information.
 Protect application routes.
 Call protected endpoints from an API.

This guide uses the Auth0 Express OpenID Connect library to secure
Express web applications. This library provides Node.js developers with an
alternative to Passport.js. Express OpenID Connect lets you add user
authentication to Express applications using security best practices while
writing less code.

If you still need to use Passport.js to secure your Express application,


please refer to the Node.js and Express Authentication Using
Passport tutorial.
How does Auth0 work?

With the help of Auth0, you don't need to be an expert on identity protocols,
such as OAuth 2.0 or OpenID Connect, to understand how to secure your
web application stack. You first integrate your application with Auth0. Your
application will then redirect users to an Auth0 customizable login page
when they need to log in. Once your users log in successfully, Auth0 takes
them back to your app, returning JSON Web Tokens (JWTs) with their
authentication and user information.

If you are short of time, check out the Auth0 Express Quickstart to get up
and running with user authentication for Express in just a few minutes.

Get the Starter Application


We have created a starter project to help you learn Node.js security
concepts through hands-on practice. The starter application
uses Bootstrap with a custom theme to take care of the styling and layout of
your application. You can focus on building Express components to secure
your application.

🛠 As such, clone the auth0-express-pug-sample repository on its starter branch


to get started:
git clone -b starter git@github.com:auth0-blog/auth0-express-pug-sample.git

🛠 Once you clone the repo, make auth0-express-pug-sample your current


directory:
cd auth0-express-pug-sample

🛠 Install the Node.js project dependencies:


npm install

🛠 Create a .env file under the project directory:


touch .env

🛠 Populate .env as follows:


DEV_PORT=4041
PROD_PORT=4040

To streamline your Node.js development workflow, this project


uses nodemon to restart the server and browser-sync to reload the
browser whenever relevant source files change.

🛠 Execute the following command to run the Node.js server:


npm run dev

You can emulate the live reload behavior of front-end frameworks such
as React and Angular in Express templates using Browsersync. The
browser will refresh automatically whenever the source code changes: for
example, when you modify a CSS rule or change the return value of a
function.
🛠 Open a separate terminal window and execute the following command to
serve the user interface of your Express app:
npm run ui

Browsersync automatically opens a new window presenting your application


user interface. If it didn't, open http://localhost:4040/.

Connect Express with Auth0


The best part of the Auth0 platform is how streamlined it is to get started by
following these steps:

Sign up and create an Auth0 Application


If you haven't already,sign up for a free Auth0 account →

A free account offers you:

 7,000 free active users and unlimited logins.


 Auth0 Universal Login for Web, iOS & Android.
 Up to 2 social identity providers like Google, GitHub, and Twitter.
 Unlimited Serverless Rules to customize and extend Auth0's
capabilities.

During the sign-up process, you create something called an Auth0 Tenant,
representing the product or service to which you are adding authentication.

🛠 Once you sign in, Auth0 takes you to the Dashboard. In the left sidebar
menu, click on "Applications".

🛠 Then, click the "Create Application" button. A modal opens up with a form
to provide a name for the application and choose its type.

 Name:
Auth0 Express Sample

 Application Type: Regular Web Applications

🛠 Click the "Create" button to complete the process. Your Auth0 application
page loads up.

In the next step, you'll learn how to help Express and Auth0 communicate.

What's the relationship between Auth0 Tenants and Auth0 Applications?

Create a communication bridge between Express and Auth0

When you use Auth0, you don't have to build login forms. Auth0 offers
a Universal Login page to reduce the overhead of adding and managing
authentication.
How does Universal Login work?

Your Express application will redirect users to Auth0 whenever they trigger
an authentication request. Auth0 will present them with a login page. Once
they log in, Auth0 will redirect them back to your Express application. For
that redirecting to happen securely, you must specify in your Auth0
Application Settings the URLs to which Auth0 can redirect users once it
authenticates them.

🛠 As such, click on the "Settings" tab of your Auth0 Application page and fill
in the following values:

🛠 Allowed Callback URLs


http://localhost:4040/callback

The above value is the URL that Auth0 can use to redirect your users after
they successfully log in.

🛠 Allowed Logout URLs


http://localhost:4040

The above value is the URL that Auth0 can use to redirect your users after
they log out.

🛠 Scroll down and click the "Save Changes" button.

🛠 Do not close this page yet. You'll need some of its information in the next
section.

Add the Auth0 configuration variables to Express

From the Auth0 Application Settings page, you need the Auth0 Domain and
Client ID values to allow your Express application to use the communication
bridge you created.

What exactly is an Auth0 Domain and an Auth0 Client ID?

🛠 Open the .env file from your auth0-express-pug-sample project directory and
update it as follows:
DEV_PORT=4041
PROD_PORT=4040
AUTH0_ISSUER_BASE_URL=https://<AUTH0_DOMAIN>/
AUTH0_CLIENT_ID=

🛠 For the AUTH0_ISSUER_BASE_URL value, <AUTH0_DOMAIN> is your Domain value


from the "Settings". Ensure that you keep the trailing slash for this value.

🛠 AUTH0_CLIENT_ID is your Client ID from the "Settings".


These variables let your Express application identify itself as an authorized
party to interact with the Auth0 authentication server.

Auth0 and Express connection set

You have completed setting up an authentication service that your Express


application can consume. All that is left is for you to continue building up the
starter project throughout this guide by implementing components to trigger
and manage the authentication flow.

Feel free to dive deeper into the Auth0 Documentation to learn more about
how Auth0 helps you save time on implementing and managing identity.

Set Up Express OpenID Connect


🛠 You need to follow these steps to integrate the Express OpenID Connect
library with your Express application.

Install Express OpenID Connect

🛠 Execute the following command:


npm install express-openid-connect

Configure Express OpenID Connect

🛠 Open the .env file once again and add a BASE_URL and SESSION_SECRET value
to it:
DEV_PORT=4041
PROD_PORT=4040
AUTH0_ISSUER_BASE_URL=<...>
AUTH0_CLIENT_ID=<...>
BASE_URL=http://localhost:4040
SESSION_SECRET=

The BASE_URL value is the URL where your application is served.

The SESSION_SECRET value is the secret used to sign the session ID cookie,
which can be either a string for a single secret or an array of multiple
secrets.

Execute the following command to generate a suitable string for the session
secret:
node -e "console.log(crypto.randomBytes(32).toString('hex'))"

Copy and paste the output of the command above as the value
for SESSION_SECRET in .env.
For your application to recognize these new environment variables, you
need to restart the Node.js server. Locate the terminal window where you
executed npm run dev earlier, stop it, and run it again.

User authentication is a mechanism to monitor who is accessing your


application and control what they can do. For example, you can prevent
users who have not logged in from accessing parts of your application. In
that scenario, Auth0 can act as your application bouncer.

A bouncer is a person employed by a nightclub or similar establishment to


prevent troublemakers from entering or to eject them from the premises.
Express security is not too different from nightclub security.

If users want to enter a protected route from your application, Auth0 will stop
them and ask them to present their credentials. If Auth0 can verify who they
are and that they are supposed to go in there, Auth0 will let them in.
Otherwise, Auth0 will take them back to a public application route.

Now, it's important to reiterate that the authentication process won't happen
within your application layer. Your Express application will redirect your
users to the Auth0 Universal Login page, where Auth0 asks for credentials
and redirects the user back to your application with the result of the
authentication process.

The Express OpenID Connect library provides the auth router to attach
authentication routes to your application. You won't have to
implement /login or /logout controllers, Express OpenID Connect takes does
that for you.

You now need to initialize, configure, and integrate express-openid-


connect with your Express application.

🛠 Open src/index.js and update the Required External Modules section to


import auth:
// src/index.js

/**
* Required External Modules
*/

const express = require('express');


const path = require('path');
const { auth } = require('express-openid-connect');

🛠 Then, update the App Configuration section to initialize and use auth as an
Express middleware function:
// src/index.js

/**
* App Configuration
*/

app.set('views', path.join(__dirname, 'views'));


app.set('view engine', 'pug');
app.use(express.static(path.join(__dirname, '..', 'public')));
app.use(
auth({
issuerBaseURL: process.env.AUTH0_ISSUER_BASE_URL,
baseURL: process.env.BASE_URL,
clientID: process.env.AUTH0_CLIENT_ID,
secret: process.env.SESSION_SECRET,
authRequired: false,
auth0Logout: true,
}),
);

You are adding two additional properties, authRequired and auth0Logout. What
are these properties doing?

authRequired is a boolean property that configures Express OpenID Connect


to require authentication for all routes when you set it to true. For this
project, you'll have a mix of public and protected routes. As such, you set
this property to false.

auth0Logout is another boolean value that enables the Auth0 logout feature,
which lets you log out a user of the Auth0 session. When implementing
logout functionality in an application, there are typically three sessions
layers you need to consider:

 Application Session Layer


 Auth0 Session Layer
 Identity Provider Session Layer

For example, if one of your users logged in using Google, you can configure
your Auth0 authentication service to log out the user from the application,
from the Auth0 session, or from Google itself. Check out the "Logout"
document to learn more details about the architecture of user logout.

For this application, you'll log out users from the Auth0 session layer.

The Express OpenID Connect library is all set up. You are ready to
implement user authentication in the next section.

Add User Authentication


Throughout this guide, you'll use Pug mixins to implement the application's
user interface (UI) following a component-based architecture. Each mixin
will act as a UI component, becoming a reusable piece that you can create
and maintain in isolation.

You need to create UI components for your users to trigger authentication


events: login, logout, and sign up.

Express OpenID Connect creates an oidc namespace in your


application's req object. In this namespace, the library stores authentication
methods and data, such as a user object to hold user profile information and
a login method to customize the user login experience. You'll explore
the oidc object in the next sections.

Create a login button

🛠 Create a login-button.pug file under the src/components/ directory:


touch src/components/login-button.pug

🛠 Create a mixin to represent a login button component


in src/components/login-button.pug like so:
mixin login-button()
button(
class="btn btn-primary btn-block",
onclick="window.location='/login'"
) Log In

Under the hood, Express OpenID Connect created a /login route for your
Express application. When the user clicks on this button, your Express
application will prompt the user to authenticate and provide consent for your
Express application to access certain data on behalf of that user. In your
current architecture, this means that your Express application redirects the
user to the Auth0 Universal Login page to carry out the authentication
process. You'll see this in action in the next sections.

You can customize the login experience further by using


the req.oidc.login() method in an Express controller. For example, you can
pass that method options to redirect users to an Auth0 Universal Login page
optimized for signing up for your Express application.

Create a sign-up button

You can make users land directly on a sign-up page instead of a login page
by creating a /sign-up route controller.

🛠 To start, open the src/index.js file. Locate the Routes Definitions section.
Under this section, there are different subsections that define routes for
each feature of your Expres web application. Locate
the > Authentication subsection, and update it as follows:
// src/index.js

/**
* Routes Definitions
*/

// > Other route subsections...

// > Authentication

app.get('/sign-up', (req, res) => {


res.oidc.login({
authorizationParams: {
screen_hint: 'signup',
},
});
});

You create a /sign-up route controller, where you access


the res.oidc.login() method. This method takes some LoginOptions to
customize the behavior of the user login experience.

Here, you override the default authorizationParams, which are URL


parameters that Express OpenID Connect uses when redirecting users to
Auth0 to log in.

You can pass new values to change what the Auth0 authorization server
returns depending on your use case. In your /sign-up controller, you specify
the screen_hint=signup property as an authorization parameter to take the
users to a sign-up form.
{
authorizationParams: {
screen_hint: "signup",
},
}

Now, create a sign-up button to trigger this event by requesting the /sign-
up route.

🛠 Create a signup-button.pug file under the src/components/ directory:


touch src/components/signup-button.pug

🛠 Populate src/components/signup-button.pug like so to define a signup-


button mixin:

mixin signup-button()
button(
class="btn btn-primary btn-block",
onclick="window.location='/sign-up'"
) Sign Up

Using the Signup feature requires you to enable the Auth0 New Universal
Login Experience in your tenant.

🛠 Open the Universal Login section of the Auth0 Dashboard and choose the
"New" option under the "Experience" subsection.
🛠 Scroll down and click on the "Save Changes" button.

The difference between the log-in and sign-up user experience will be more
evident once you integrate those components with your Express application
and see them in action. You'll do that in the next sections.

Create a logout button

🛠 Create a logout-button.pug file under the src/components/ directory:


touch src/components/logout-button.pug

🛠 Populate src/components/logout-button.pug like so:


mixin logout-button()
button(
class="btn btn-danger btn-block",
onclick="window.location='/logout'"
) Log Out

The /logout route created by Express OpenID Connect calls


the req.oidc.logout() method under the hood. This method clears the
application session and redirects to the Auth0 /v2/logout endpoint to clear
the Auth0 session. As with the login method, you can
pass LogoutOptions to req.oidc.logout() to customize its behavior.
Here, you pass the returnTo option to specify the URL where Auth0 should
redirect your users after they logout. Right now, you are working locally, and
your Auth0 application's "Allowed Logout URLs" point
to http://localhost:4040.

However, if you were to deploy your Express application to production, you


need to add the production logout URL to the "Allowed Logout URLs" list
and ensure that Auth0 redirects your users to that production URL and
not localhost.

Read more about how Logout works at Auth0.

Integrate the login and logout buttons

Let's wrap the login-button and logout-button mixins into a mixin


called authentication-button.

🛠 Create an authentication-button.pug file under the src/components/ directory:


touch src/components/authentication-button.pug

🛠 Populate src/components/authentication-button.pug with the following code:


include ./login-button
include ./logout-button

mixin authentication-button(isAuthenticated)
if isAuthenticated
+logout-button
else
+login-button

isAuthenticated is a boolean value exposed by the req.oidc object. Its value


is true when Auth0 has authenticated the user and false when it hasn't.

There are some advantages to using this authentication-button mixin


wrapper:

You can build flexible interfaces. authentication-button serves as a "log in/log


out" switch that you can put anywhere you need that switch functionality.
However, you still have separate login-button and logout-button mixins for
cases when you need their functionality in isolation. For example, you may
have a logout button on a page that only authenticated users can see.

You can build extensible interfaces. You can easily swap the login-
button mixin with the signup-button mixin in authentication-button to create a
"sign up/log out" switch. You could also wrap the "sign up/log out" switch in
a new-authentication-button mixin.

You can build declarative interfaces. Using authentication-button, you can


add login and logout functionality to a navigation bar component, for
example, without thinking about the implementation details of how the
authentication switch works.
🛠 With that in mind, create an auth-nav.pug file under
the src/components/ directory:
touch src/components/auth-nav.pug

🛠 Populate src/components/auth-nav.pug like so:


include ./authentication-button

mixin auth-nav(isAuthenticated)
div(class="navbar-nav ml-auto")
+authentication-button(isAuthenticated)

isAuthenticated makes another appearance. Where is that value coming


from? You'll find out soon!

🛠 Finally, open nav-bar.pug under the src/components/ directory and update it


like so:
include ./main-nav
include ./auth-nav

mixin nav-bar(activeRoute)
div(class="nav-container mb-3")
nav(class="navbar navbar-expand-md navbar-light bg-light")
div(class="container")
div(class="navbar-brand logo")
+main-nav(activeRoute)
+auth-nav(isAuthenticated)

By having different types of navigation bar subcomponents, you can extend


each as you need without reopening and modifying the main nav-
bar component.

Once again, isAuthenticated shows up. The Express OpenID Connect library
defines this value in the req.oidc.isAuthenticated() method. Its return value is
essential for authentication to work correctly in your Express app.

How do you pass data from a controller to a template in Express?

In Express web applications, you have access to a one-way data flow from
route controller to template. As such, each route controller that renders a
template that depends on isAuthenticated must pass down this value.

However, passing a value manually to a template on each route controller is


not only tedious but error-prone. What you can do instead is to make the
value available as a local value to all Pug templates.

🛠 Update the App Configuration section in src/index.js as follows:


// src/index.js

/**
* App Configuration
*/

app.set('views', path.join(__dirname, 'views'));


app.set('view engine', 'pug');

app.use(express.static(path.join(__dirname, '..', 'public')));

app.use(
auth({
issuerBaseURL: process.env.AUTH0_ISSUER_BASE_URL,
baseURL: process.env.BASE_URL,
clientID: process.env.AUTH0_CLIENT_ID,
secret: process.env.SESSION_SECRET,
authRequired: false,
auth0Logout: true,
}),
);

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


res.locals.isAuthenticated = req.oidc.isAuthenticated();
next();
});

You define res.locals within a middleware function handler. This object lets
you pass data around your Express application. All of your Pug templates
can access its properties (such as isAuthenticated) directly.
Since req.oidc.isAuthenticated() is a method, you have to execute it to get its
value.

There is one caveat about using res.locals: these values only live within an
individual request. As soon as the request-response cycle is complete, the
values are gone. This isn't a problem for your application since each time a
user requests a route from the browser, the request-response cycle starts all
over again.

Read more details about res.locals from StackOverflow.

🛠 Go ahead and try to log in. Your Express application redirects you to the
Auth0 Universal Login page. You can use a form to log in with a username
and password or a social identity provider like Google. Notice that this login
page also gives you the option to sign up.
Experiment: Use the signup-button mixin

You can customize the appearance of New Universal Login pages. You can
also override any text in the New Experience using the Text Customization
API.

🛠 Click on the Profile tab and then click on the "Log Out" button.

Notice that Express logged you out, but instead of taking you back to
the /profile route, it took you back to the / route, the home page.

🛠 Click on the Profile tab and now click on the "Log In" button.

This time, Express takes you again back to the home page, / after you log
in. As a user, you would expect to access the /profile page after you log in,
right? After all, your authentication system is acting like a bouncer. The
bouncer doesn't take people back to the nightclub entrance after they
present their ID. The bouncer lets them pass through and access the VIP
lounge or whatever room the bouncer is protecting.

Why is this home page redirect happening?

This Express web app is using static routes to render its user interface. You
map a user interface action with a server endpoint or controller. This
mapping is hard-coded so far.

The /login route controller that the Express OpenID Connect library created
for you has a hard-coded value for the path to which Auth0 should return
users after they log in. That default value is the root of your server URL, /.

However, what if the /profile page had both public and protected
resources? In a scenario like that, anyone can visit the /profile page to read
its public information. Then, users can log in to read protected information.
The best user experience is for the users to return to the /profile page after
they log in, not the home page.

One way to fix this home-page redirect is to create a dedicated route for
each type of login and logout:
GET /sign-up-profile

GET /sign-up-external-api

GET /login-profile

GET /login-external-api

GET /logout-profile

GET /logout-external-api

However, this method won't scale well at all. Imagine if you had more than
10 different pages that require that smooth login experience.

It would be better to create a single dynamic route that can handle different
"types" of login and logout actions:
GET /sign-up/:page

GET /login/:page

GET /logout/:page
Since the /sign-uproute behaves very much like the /login route, you are
enhancing that route too — in case that you want to use the "Sign Up"
button in your application.

Then you could take that :page parameter and use it to tell Auth0 to return
users to serverUrl/page after they log in or log out.

To implement these new authentication route controllers easily, you can


leverage the activeRoute property that you are passing from your route
controllers to your templates. Take a look at the /profile route controller, for
example:
app.get('/profile', (req, res) => {
res.render('profile', { activeRoute: req.originalUrl });
});

You pass down this { activeRoute: req.originalUrl } object in all route


controllers. You recently learned how to leverage res.locals to make the
authentication status of the user available to your whole Express
application. You can do the same for the activeRoute property.

🛠 The steps that follow will show you how to create dynamic authentication
routes. However, if you want Express to redirect all users who log out to the
home page, you can leave your application as it is.

🛠 Update the App Configuration section in src/index.js as follows:


// src/index.js

/**
* App Configuration
*/

app.set("views", path.join(__dirname, "views"));


app.set("view engine", "pug");

app.use(express.static(...));

app.use(
auth({...})
);

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


res.locals.isAuthenticated = req.oidc.isAuthenticated();
res.locals.activeRoute = req.originalUrl;
next();
});

You now define another local variable that all Pug templates can
access: res.locals.activeRoute. You no longer need to pass activeRoute down
to your templates from each controller.

🛠 Locate the Routes Definitions section in src/index.js. Update


the > Home, > Profile, and > External API subsections as follows:
// src/index.js

/**
* Routes Definitions
*/

// > Home

app.get('/', (req, res) => {


res.render('home');
});

// > Profile

app.get('/profile', (req, res) => {


res.render('profile');
});

// > External API

app.get('/external-api', (req, res) => {


res.render('external-api');
});

🛠 Now, you need to create the sign-


up/:page, login/:page and logout/:page route controllers. Head back to
the Routes Definitions section in src/index.js. Update
the > Authentication subsection as follows:
// src/index.js

/**
* Routes Definitions
*/
// > Authentication

app.get('/sign-up/:page', (req, res) => {


const { page } = req.params;

res.oidc.login({
returnTo: page,
authorizationParams: {
screen_hint: 'signup',
},
});
});

app.get('/login/:page', (req, res) => {


const { page } = req.params;

res.oidc.login({
returnTo: page,
});
});

app.get('/logout/:page', (req, res) => {


const { page } = req.params;

res.oidc.logout({
returnTo: page,
});
});

Now, you need to update your login and logout buttons to use these custom
route controllers instead of the default ones created by Express OpenID
Connect.

🛠 Update src/components/signup-button.pug as follows:


mixin signup-button()
button(
class="btn btn-primary btn-block",
onclick=`window.location='/sign-up/${activeRoute}'`
) Sign Up

🛠 Update src/components/login-button.pug as follows:


mixin login-button()
button(
class="btn btn-primary btn-block",
onclick=`window.location='/login/${activeRoute}'`
) Log In

🛠 Update src/components/logout-button.pug as follows:


mixin logout-button()
button(
class="btn btn-danger btn-block",
onclick=`window.location='/logout/${activeRoute}'`
) Log Out
activeRoute is available in any template without the need to pass it down from
mixin to mixin.

🛠 Visit the "Profile" page and try to log in or log out.


If you log in, notice that you come back to the "Profile" page after you log in
using the Auth0 Universal Login Page.

If you log out, you get an error!

Why are you getting an error when logging out from the /profile page?

If you click on the "See details for this error" link from the error page, you'll
learn that the error relates to an invalid_request: The "returnTo" querystring
parameter "http://localhost:4040/profile " is not defined as a valid URL in
"Allowed Logout URLs".

During the Auth0 setup section of this guide, you defined "Allowed Logout
URLs" for the Auth0 application that represents your Express web
application in the Auth0 platform:
Allowed Logout URLs
http://localhost:4040

Auth0 can only redirect your users after they log out to the URLs listed in
that field. As such, you need to add the /profile and /external-api paths to it.

🛠 Head back to the "Applications" section from the Auth0 Dashboard. Select
your "Auth0 Express Sample" application and then click on the "Settings"
tab.

🛠 Locate Allowed Logout URLs and update like so:


http://localhost:4040,
http://localhost:4040/profile,
http://localhost:4040/external-api

🛠 Scroll down and click on "Save Changes".

🛠 Head back to your application user interface in the browser. Visit either
the "Profile" or "External API" page. Refresh the page and try to log in and
log out. You should now stay in the same page after either action completes
without any errors.

In this section, you have learned how to use the built-


in /login and /logout route controllers exposed by the Express OpenID
Connect library. You also learned how to create custom authentication
controllers to improve the user experience of your application and to
accommodate to different use cases.

In the next section, you'll learn how to retrieve and display user profile
information in your user interface.

Retrieving User Information


You can use profile data stored in your Auth0 user database to personalize
the user interface of your Express application. The Express OpenID
Connect library exposes that profile data in the req.oidc.user object. Some of
the user information available includes the name, nickname, picture, and
email of the logged-in user.

How can you use req.oidc.user to create a profile page for your users?

🛠 Update the /profile route controller under the Routes


Definitions > Profile section in src/index.js as follows:

// src/index.js

/**
* Routes Definitions
*/

// > Profile
app.get('/profile', (req, res) => {
res.render('profile', {
user: req.oidc.user,
});
});

🛠 Next, update the /profile template defined in src/views/profile.pug as


follows:
extends ../components/layout

block content
if user
div
div(class="row align-items-center profile-header")
div(class="col-md-2 mb-3")
img(
class="rounded-circle img-fluid profile-picture mb-3 mb-md-0"
src=user.picture
alt="Profile"
)
div(class="col-md text-center text-md-left")
h2 #{user.name}
p(class="lead text-muted") #{user.email}
div(class="row")
pre(class="col-12 text-light bg-dark p-4")
| #{JSON.stringify(user, null, 2)}

What's happening within the profile template?

 You obtain the user name, picture, and email from the user object that
you passed to the template from the /profile route controller.

 You then display these three properties in the user interface. You only
render the content of the profile template if the user object is defined.

 Finally, you display the full content of the decoded ID token within a
code box. You can now see all the other properties available for you
to use.

What is an ID token?

The profile template renders user information that you could consider
protected. Additionally, the user property is null if there is no logged-in user.
So either way, this component should only render if Auth0 has authenticated
the user.

As such, you should protect the route that renders this


template, http://localhost:4040/profile. You'll learn how to do just that in the
next section.

Protecting Routes
The Express OpenID Connect library exposes a requiresAuth() middleware
function that you can use to require users to login in order to access a
specific route. Express will redirect to the Auth0 Universal Login page any
users who have not logged in and try to access the route.

As a reminder: for requiresAuth() to work, you must


set authRequired to false when you initialize Express OpenID Connect using
the auth middleware function.

🛠 Open src/index.js and update the Required External Modules section as


follows:
// src/index.js

/**
* Required External Modules
*/

const express = require('express');


const path = require('path');
const { auth, requiresAuth } = require('express-openid-connect');

You can add the requiresAuth() middleware function on as part of the


request-response cycle of each controller that you want to protect — in this
case, /profile and /external-api.

🛠 Update the Routes Definitions > Profile subsection of src/index.js as


follows:
/**
* Routes Definitions
*/

// > Profile

app.get('/profile', requiresAuth(), (req, res) => {


res.render('profile', {
user: req.oidc.user,
});
});

You might also like