Bootstrap components in Angular (ng-bootstrap)

The ng-bootstrap, allow us to use Bootstrap Components and directive in Angular 4+ through ng-bootstrap. This makes it easy to use Bootstrap in your Angular apps.

Angular 4+ is required to use ng-bootstrap. ng-bootstrap depends on Bootstrap’s CSS being available, but you don’t need the Bootstrap JS or jQuery dependencies.

As the Bootstrap 4 contains many different JavaScript-dependent components. Many of these components rely on jQuery for Document Object Model (DOM) manipulation and can adversely interact with Angular’s own View Encapsulation based data-binding. We will solve this issue using the Angular friendly versions of these components provided by the ng-bootstrap project.

Step 1: Install the bootstrap through npm

To get started with Bootstrap in our Angular project, we will first have to install it as a dependency:
     $ npm install –save bootstrap@next
The @next will install the latest version of Bootstrap 4 and not the bootstrap 3 stable version.

Step 2: Importing bootstrap CSS or SCSS file

Once we have installed Bootstrap, we have to import our bootstrap scss file in own Sass modules. We simply add an import statement to the top of our /src/styles.scss file in our Angular project:

@import ‘~bootstrap/scss/bootstrap’;

This imports all of the Bootstrap using a special loader mechanism provided by sassloader. Our Angular application now has all of the Bootstrap 4 CSS framework available and ready to use.

Or

We can import our bootstrap CSS file in style.css of our angular project as

@import “~bootstrap/dist/css/bootstrap.css”

To make the Bootstrap CSS classes available for the components in our project we need to include the Bootstrap CSS file from node_modules/bootstrap/dist/css/bootstrap.css in our project.

Or

We have another option of importing our bootstrap file by  just add the following code in the styles array of the .angular-cli.json file:

“../node_modules/bootstrap/dist/css/bootstrap.min.css”,

Step 3: We have to import our ng-bootstrap module in app.module.ts file

import {NgbModule} from '@ng-bootstrap/ng-bootstrap';
....
  imports: [
    BrowserModule,
    NgbModule.forRoot()
  ],

})
export class AppModule { }

 

Step 4: Use the ng-bootstrap Component

Now that we have imported both Bootstrap-4 and ng-bootstrap module in our apps, we can use any of ng-bootstrap components it provides to us. Let’s add some of ng-bootstrap component : 

Add the following code in app.component.html file

<div class="jumbotron">
  <div class="container text-center">
    <ngb-alert type="success" [dismissible]="false">
      ng-bootstrap Working
    </ngb-alert>

    <h1>
      <i class="fa fa-bath" aria-hidden="true"></i>
      Bootstrap jumbotron
    </h1>
  </div>
</div>


<p>
  <ngb-alert [dismissible]="false">
    <strong>Warning!</strong> Better check yourself, you're not looking too good.
  </ngb-alert>
</p>

<div class="container">
  <p>
    A progress bar:
    <ngb-progressbar showValue="true" type="warning" [value]="85">
    </ngb-progressbar>
  </p>
</div>
<br/><br/>
<div class="container">
    <p>Popup box</p>
    <button type="button" class="btn btn-outline-secondary" placement="top"
    ngbPopover="Vivamus sagittis lacus vel augue laoreet rutrum faucibus." popoverTitle="Popover on top">
      Popover on top
    </button>
</div>
<div class="container">
  <p>Rating</p>
  <ngb-rating [(rate)]="currentRate"></ngb-rating>
  <hr>
  <pre>Rate: <b>{{currentRate}}</b></pre>
</div>



Express Routing

In an Express, we can route to the particular URI (Uniform Resources Identifier) through HTTP Client request method (GET, POST, DELETE, PUT and so on).

const router = express.Router();
Router class: In express have router class, we can use router class method on the HTTP verbs – GET, PUT, DELETE and etc.

The syntax of routes in an Express application − app.method(path, handler) The path is the route at which the request will run and each route can have one or more handler functions, which are executed when the route is matched.
Example :

router.get(‘/’, (req, res, next) => {
   res.send(‘ARTICLES’);
});

 


In an example below we are using an express route to access the resources of HTTP get / or root, /about, /contact etc.

Step 1: First create app.js file in root folder, add the following code 

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

//port 

const port = 3000;
//init app

const app = express();
const index = require('./routes/index');
const articles = require('./routes/articles');
const categories = require('./routes/categories');
const manage = require('./routes/manage');
const manage = require('./routes/blog');

//set static folder

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

app.use('/', index);
app.use('/articles', articles);
app.use('/categories', categories);
app.use('/manage', manage);

app.listen(port, () =>{
    console.log('Server startd on port ' +port);
})

 

Step 2: Define routing for index, /about and /contact page

In root folder create a folder called routes, create following file index.js, about.js and contact.js file. Add the following code in index.js file

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

router.get('/', (req, res, next) => {
    res.send('INDEX');
});

module.exports = router;

Add route code for about.js file

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

router.get('/', (req, res, next) => {
    res.send('ABOUT');
});

module.exports = router;

Add route code for contact.js file

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

router.get('/', (req, res, next) => {
    res.send('CONTACT');
});

module.exports = router;

NOTE: We can access root file as http://localhost:3000, we can access about page at http://localhost:3000/about

 

Example 2 : We are accessing the sub path, eg we are accessing the http://localhost:3000/blog/articles/add.

Step 1: In the routes, folder adds a new file called blog.js file to access the routing code for blog and blog/articles/add.

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

router.get('/', (req, res, next) => {
    res.send('BLOG');
});

router.get('/articles/add', (req, res, next) => {
    res.render('add_article', {title: 'Create Article'});
});

module.exports = router;

 

Step 2: Create a folder view in the root folder and add two new files for the template, add_article.pug and layout.pug. Add the following code in layout.pug file

doctype html
html
  head
    title BooksBlog
  body
    block content

add the following code in add_article.pug file

extends layout

block content
  h1 #{title}

 

 

Example 3: Accessing the particular sub-path like particular articles like http://localhost:3000/manage/books/edit/2

Step 1:  We will first add manage.js code of route in routes folder.  We can access to http://localhost:3000/manage/books/edit/2, http://localhost:3000/manage/books, http://localhost:3000/manage/books/add

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

router.get('/books', (req, res, next) => {
  res.render('manage_books', {title: 'Manage books'});
});

router.get('/books/add', (req, res, next) => {
  res.render('add_book', {title: 'Create book'});
});

router.get('/books/edit/:id', (req, res, next) => {
  res.render('edit_book', {title: 'Edit book'});
});

module.exports = router;

Step 2: In view folder, we will have to add 3 file books.pug, edit_book.pug and edit_book.pug. We will add code for books.pug and same code can be added to other two files.

extends layout

block content
  h1 #{title}

 

Express OAuth strategies Login for Facebook

OAuth 2.0 is a delegation protocol, a means of letting someone who controls a resource allow a software application to access that resource on their behalf without impersonating them. Application using an external provider to register the web application, without the need to input their username and password. OAuth is mainly used by social platforms, such as Facebook, Twitter, and Google, to allow users to register with other websites using their social account.

Setting up OAuth strategies

Passport supports the basic OAuth strategy, which enables you to implement any OAuth-based authentication. However, it also supports a user authentication through major OAuth providers using wrapper strategies that help you avoid the need to implement a complex mechanism.

First, we have to create developer account from the OAuth provider, This application will have both an OAuth client ID and an OAuth client secret, which will allow you to verify your application against the OAuth provider.

Handling OAuth user creation

The OAuth user creation should be a bit different than the local signup() method. Since users are signing
up using their profile from other providers, the profile details are already present, which means you will
need to validate them differently. To do so, go back to your app/controllers/users.server.controller.js file, and add the following module method:

 

 

 

 

 

 

Using Passport’s Facebook strategy

Facebook is probably the world’s largest OAuth provider. Many modern web applications offer their users the ability to register with the web application using their Facebook profile. Passport supports Facebook OAuth authentication using the passport-facebook module.

Installing Passport’s Facebook strategy

npm install passport-facebook --save
npm install

 

Configuring Passport’s Facebook strategy

Before you begin configuring your Facebook strategy, you will have to go to Facebook’s developer home page at https://developers.facebook.com/, create a new Facebook application, and set the local host as the application domain. After configuring your Facebook application, you will get a Facebook application ID and secret. You’ll need those to authenticate your users via Facebook, so let’s save them in our environment configuration file. Go to the config/env/development.js file and change it as follows:

Introducing Mongoose

Mongoose is a Node.js module that provides developers with the ability to model objects and save
them as MongoDB documents. While MongoDB is a schemaless database, Mongoose offers you the
opportunity to enjoy both strict and loose schema approaches when dealing with Mongoose models.

Mongoose provides a straight-forward, schema-based solution to model your application data. It includes built-in type casting, predefine and custom validation, query building, business logic hooks and more, out of the box.

 

The basic features of Mongoose:

    • Mongoose schemas and models
    • Verifying your data using predefined and custom validators
    • Using middleware to intercept the model’s methods
    • Schema indexes, modifiers, and virtual attributes
    • Using the model’s methods and performing CRUD operations

Installing the mongoose: npm install –save mongoose, npm install

Contacting to MongoDB:
To connect to MongoDB, we will need to use the MongoDB connection URI.

mongodb://username:password@hostname:port/database

Since you’re connecting to a local instance, we can skip the username and password and use the
following URI:
mongodb://localhost/test

Defining URI in mongoose

mongoose.connect('mongodb://localhost/test');

 

Step 1: When a building a real application, saving the URI directly in the config/express.js
file is a bad practice. The best way store application variables are to use your environment
configuration file. Go to your config/env/development.js file and add the following code.

// Set the 'development' environment configuration object
module.exports = {
	db: 'mongodb://localhost/mean-development',
	sessionSecret: 'developmentSessionSecret'
};

In the real application, we need to define mongoose URI in config/env/production.js

Step 2: We required the Mongoose module and connected to the MongoDB instance using the db property of your configuration object. To In config folder, create a new file named config/mongoose.js , which contains the following code
snippet:

const config = require('./config');
const mongoose = require('mongoose');
module.exports = function() {
   const db = mongoose.connect(config.db);
   return db;
};

Add the following code in config/config.js

// Load the correct configuration file according to the 'NODE_ENV' variable
module.exports = require('./env/' + process.env.NODE_ENV + '.js');

 

Step 3: To initialize Mongoose configuration in server.js or app.js in root folder, add the following highlight code as

process.env.NODE_ENV = process.env.NODE_ENV || 'development';
const configureMongoose = require('./config/mongoose');
const configureExpress = require('./config/express');
const db = configureMongoose();
const app = configureExpress();

app.listen(3000);
module.exports = app;
console.log('Server running at http://localhost:3000/');

 

Local Login strategy

Passport’s local strategy is a Node.js module that allows you to implement a username/password
authentication mechanism. Along with it, we need other modules as dependency as follow

{
  "name": "local-strategy",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "tamo",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.17.2",
    "compression": "^1.7.0",
    "ejs": "^2.5.6",
    "express": "^4.15.3",
    "express-session": "^1.15.3",
    "method-override": "*",
    "mongoose": "*:",
    "morgan": "*",
    "passport": "*"
  }
}

Run>> npm install

Step 1: Configuring Passport

To create the Passport configuration file, we have to create config folder in the root and create a new file named passport.js and express.js.  In the root folder, we have server.js or usually, we called it as app.js. Add the following code in server.js

//Set the 'NODE_ENV'  variable
process.env.NODE_ENV = process.env.NODE_ENV || 'development';

//Load the module dependencies
const configureMongoose = require('./config/mongoose');
const configureExpress = require('./config/express');
const configurePassport = require('./config/passport');

//Create a new Mongoose Connection instance
const db = configureMongoose();

//Create a new Express application instance
const app = configureExpress();

//Configure the passport middleware
const passport = configurePassport();

app.listen(3000);
console.log('Server running at http://localhost:3000/');

module.exports = app;

 

Step 2: Register the Passport middleware

We required the Passport module and need to register the Passport middleware in your Express application and add the following code in config/express.js. The registered two middleware: the

  1. passport.initialize() middleware, which is responsible for bootstrapping the Passport module, and the
  2. passport.session() middleware, which is using the Express session to keep track of your user’s session.
const config = require('./config');
const express = require('express');
const morgan = require('morgan');
const compress = require('compression');
const bodyParser = require('body-parser');
const methodOverride = require('method-override');
const session = require('express-session');

const flash = require('connect-flash');

const passport = require('passport');

module.exports = function() {
    const app = express();
    
    if (process.env.NODE_ENV === 'development') {
        app.use(morgan('dev'));
    } else if (process.env.NODE_ENV === 'production') {
        app.use(compress());
    }
    app.use(bodyParser.urlencoded({
        extended: true
    }));
    
    app.use(bodyParser.json());
    app.use(methodOverride());

    app.use(session({
        saveUninitialized: true,
        resave: true,
        secret: config.sessionSecret
    }));

    app.set('views', './app/views');
    app.set('view engine', 'ejs');

    app.use(passport.initialize());
    app.use(passport.session());
    
    app.use(flash());

    require('../app/routes/index.server.routes.js')(app);
    require('../app/routes/users.server.routes.js')(app);
    app.use(express.static('./public'));
    return app;
};

The passport module is installed and configure, now we need to install at least one strategy for authentication, here we are using local strategy. For local strategy we need “passport-local”  as dependency >> npm install –save passport-local

 

Step 3: Configure the local strategy

We need to configure the local strategy, we will keep the each strategy separately in folder strategies in the config folder.  To use local strategy we need to install npm package called “passport-local”. Add the local strategy code in config/strategies/local.js

// Load the module dependencies
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const User = require('mongoose').model('User');

// Create the Local strategy configuration method

module.exports = function() {
	// Use the Passport's Local strategy 

	passport.use(new LocalStrategy(function(username, password, done) {
		// Use the 'User' model 'findOne' method to find a user with the current username

		User.findOne({
			username: username
		}, (err, user) => {
			// If an error occurs continue to the next middleware

			if (err) {
				return done(err);
			}
			
			// If a user was not found, continue to the next middleware with an error message

			if (!user) {
				return done(null, false, {
					message: 'Unknown user'
				});
			}

			// If the passport is incorrect, continue to the next middleware with an error message

			if (!user.authenticate(password)) {
				return done(null, false, {
					message: 'Invalid password'
				});
			}
			
			// Otherwise, continue to the next middleware with the user object

			return done(null, user);
		});
	}));
};

For local strategy, we need above highlight code module. We register the strategy using the passport.use() method, which uses an instance of the LocalStrategy object. Notice how the LocalStrategy constructor takes a callback function as an argument. It will later call this callback when trying to authenticate a user.
The callback function accepts three arguments—username , password , and a done callback—which will be called when the authentication process is over. Inside the callback function, you will use the User Mongoose model to find a user with that username and try to authenticate it. In the event of an error, you will pass the error object to the done callback. When the user is authenticated, you will call the done callback with the user Mongoose object.

 

Step 4: Passport will handle users serialization/deserialization

Now we will create passport.js in the config folder, the passport will handle users serialization.  When a user is authenticated, Passport will save its _id property to the session. Later on, when the user object is needed, Passport will use the _id property to grab the user object from the database through deserializing. Add the following code config/passport.js

// Load the module dependencies
const passport = require('passport');
const mongoose = require('mongoose');

// Define the Passport configuration method
module.exports = function() {
	// Load the 'User' model

	const User = mongoose.model('User');
	
	// Use Passport's 'serializeUser' method to serialize the user id

	passport.serializeUser((user, done) => {
		done(null, user.id);
	});

	// Use Passport's 'deserializeUser' method to load the user document

	passport.deserializeUser((id, done) => {
		User.findOne({
			_id: id
		}, '-password -salt', (err, user) => {
			done(err, user);
		});
	});

	// Load Passport's strategies configuration files

	require('./strategies/local.js')();
};

Here along with serialization,  we are doing two important task

  1. Loading or including local strategy configuration file.
  2. Notice how we used the field options argument to make sure Mongoose doesn’t fetch the user’s password and salt properties.

 

Step 5: Adapting the User model

In the User Model, we have to define the UserSchema, adding some pre middleware, and adding some new instance methods. To do so, go to your app/models/user.js or user.server.model.js file, and add the following code

// Load the module dependencies
const mongoose = require('mongoose');
const crypto = require('crypto');
const Schema = mongoose.Schema;

// Define a new 'UserSchema'
const UserSchema = new Schema({
	firstName: String,
	lastName: String,
	email: {
		type: String,
		// Validate the email format

		match: [/.+\@.+\..+/, "Please fill a valid email address"]
	},
	username: {
		type: String,
		// Set a unique 'username' index

		unique: true,
		// Validate 'username' value existance

		required: 'Username is required',
		// Trim the 'username' field

		trim: true
	},
	password: {
		type: String,
		// Validate the 'password' value length

	validate: [
			(password) => password && password.length > 6,
			'Password should be longer'
		]
	},
	salt: {
		type: String
	},
	provider: {
		type: String,
		// Validate 'provider' value existance

		required: 'Provider is required'
	},
	providerId: String,
	providerData: {},
	created: {
		type: Date,
		// Create a default 'created' value

		default: Date.now
	}
});

// Set the 'fullname' virtual property
UserSchema.virtual('fullName').get(function() {
	return this.firstName + ' ' + this.lastName;
}).set(function(fullName) {
	const splitName = fullName.split(' ');
	this.firstName = splitName[0] || '';
	this.lastName = splitName[1] || '';
});

// Use a pre-save middleware to hash the password
UserSchema.pre('save', function(next) {
	if (this.password) {
		this.salt = new Buffer(crypto.randomBytes(16).toString('base64'), 'base64');
		this.password = this.hashPassword(this.password);
	}

	next();
});

// Create an instance method for hashing a password
UserSchema.methods.hashPassword = function(password) {
	return crypto.pbkdf2Sync(password, this.salt, 10000, 64).toString('base64');
};

// Create an instance method for authenticating user
UserSchema.methods.authenticate = function(password) {
	return this.password === this.hashPassword(password);
};

// Find possible not used username or new unique username
UserSchema.statics.findUniqueUsername = function(username, suffix, callback) {
	// Add a 'username' suffix

	const possibleUsername = username + (suffix || '');

	// Use the 'User' model 'findOne' method to find an available unique username

	this.findOne({
		username: possibleUsername
	}, (err, user) => {
		// If an error occurs call the callback with a null value, otherwise find find an available unique username
		if (!err) {
			// If an available unique username was found call the callback method, otherwise call the 'findUniqueUsername' method again with a new suffix
			if (!user) {
				callback(possibleUsername);
			} else {
				return this.findUniqueUsername(username, (suffix || 0) + 1, callback);
			}
		} else {
			callback(null);
		}
	});
};

// Configure the 'UserSchema' to use getters and virtuals when transforming to JSON
UserSchema.set('toJSON', {
	getters: true,
	virtuals: true
});

// Create the 'User' model out of the 'UserSchema'
mongoose.model('User', UserSchema);

First, you added four fields to your UserSchema object: a salt property, which you’ll use to hash your password; a provider property, which will indicate the strategy used to register the user; a providerId property, which will indicate the user identifier for the authentication strategy; and a providerData property, which you’ll later use to store the user object retrieved from OAuth providers.

Activity done in User models

  1. We define user schema.
  2. Pre-save middleware to handle the hashing of user passwords.
  3. Create two instance methods: a hashPassword() instance method, which is used to hash a
    password string by utilizing Node.js, crypto module; and an authenticate() instance method, which accepts a string argument, hashes it, and compares it to the current user’s hashed password.
  4. findUniqueUsername() static method, which is used to find an available unique
    username for new users

 

Step 5: Add authentication views

We need to add the user signup and signin view page,  add code for app/views/signup.ejs in views.

<!DOCTYPE html>
<html>
<head>
	<!-- Use the 'title' property to render a page title  -->

	<title><%= title %></title>
</head>
<body>
  	<!-- Display flash messages  -->

	<% for(var i in messages) { %>
	   <div class="flash"><%= messages[i] %></div>
	<% } %>

	<!-- Render the signup form  -->

	<form action="/signup" method="post">
		<div>
			<label>First Name:</label>
			<input type="text" name="firstName" />
		</div>
		<div>
			<label>Last Name:</label>
			<input type="text" name="lastName" />
		</div>
		<div>
			<label>Email:</label>
			<input type="text" name="email" />
		</div>
		<div>
			<label>Username:</label>
			<input type="text" name="username" />
		</div>
		<div>	
			<label>Password:</label>
			<input type="password" name="password" />
		</div>
		<div>
			<input type="submit" value="Sign up" />
		</div>
	</form>

	<!-- Render the OAuth authentication links  -->

	<a href="/oauth/facebook">Sign in with Facebook</a>
	<a href="/oauth/twitter">Sign in with Twitter</a>
	<a href="/oauth/google">Sign in with Google</a>
</body>
</html>

Adding code for view for signin.ejs. app/views/signin.ejs

<!DOCTYPE html>
<html>
<head>
	<!-- Use the 'title' property to render a page title  -->
	<title><%= title %></title>
</head>
<body>
  	<!-- Display flash messages  -->
	<% for(var i in messages) { %>
	   <div class="flash"><%= messages[i] %></div>
	<% } %>

	<!-- Render the signin form  -->
	<form action="/signin" method="post">
		<div>
			<label>Username:</label>
			<input type="text" name="username" />
		</div>
		<div>
			<label>Password	:</label>
			<input type="password" name="password" />
		</div>
		<div>
			<input type="submit" value="Sign In" />
		</div>
	</form>

	<!-- Render the OAuth authentication links  -->
	<a href="/oauth/facebook">Sign in with Facebook</a>
	<a href="/oauth/twitter">Sign in with Twitter</a>
	<a href="/oauth/google">Sign in with Google</a>
</body>
</html>

 

Step 6: Modifying the Users controller

To alter the Users controller, go to your app/controllers/users.server.controller.js file, and
change its content as follows:

const User = require('mongoose').model('User');
const passport = require('passport');

function getErrorMessage(err) {
    let message = '';
    if (err.code) {
        switch (err.code) {
            case 11000:
            case 11001:
                message = 'Username already exists';
                break;
            default:
                message = 'Something went wrong';
        }
    } else {
        for (var errName in err.errors) {
            if (err.errors[errName].message) message = err.errors[errName].message;
        }
    }
    return message;
};

exports.renderSignin = function(req, res, next) {
    if (!req.user) {
        res.render('signin', {
        title: 'Sign-in Form',
        messages: req.flash('error') || req.flash('info')
    });
    } else {
        return res.redirect('/');
    }
};


exports.renderSignup = function(req, res, next) {
    if (!req.user) {
        res.render('signup', {
            title: 'Sign-up Form',
            messages: req.flash('error')
        });
    } else {
        return res.redirect('/');
    }
};


exports.signup = function(req, res, next) {
    if (!req.user) {
        const user = new User(req.body);
        user.provider = 'local';
        user.save((err) => {
            if (err) {
                const message = getErrorMessage(err);
                req.flash('error', message);
                return res.redirect('/signup');
            }
            req.login(user, (err) => {
                if (err) return next(err);
                    return res.redirect('/');
            });
        });
    } else {
        return res.redirect('/');
    }
};


exports.signout = function(req, res) {
    req.logout();
    res.redirect('/');
};

Here we are displaying various error message while signup and login, and also creating a new user. The signup() method uses your User model to create new users. As you can see, it first creates a user object from the HTTP request body. Then, try saving it to MongoDB. If an error occurs, the signup() method will use the getErrorMessage() method to provide the user with an appropriate error message. The getErrorMessage() method is a private method that returns a unified error message from a Mongoose error object. There are two possible errors here:

  1. MongoDB indexing error handled using the error code
  2. Mongoose validation error handled using the err.errors object.

The signout() method is also simple and uses the req.logout() method, which is provided by the Passport module to invalidate the authenticated session.

 

Step 7: Displaying flash error messages

When an authentication process is failing, it is common to redirect the request back to the signup or sign-in pages. This is done here when an error occurs, but how can your user tell what exactly went wrong? The problem is that when redirecting to another page, you cannot pass variables to that page. The solution is to use some sort of mechanism to pass temporary messages between requests. Fortunately, that mechanism already exists in the form of a node module named Connect-Flash .

The Connect-Flash module is a node module that allows you to store temporary messages in an area of the session object called flash . Messages stored on the flash object will be cleared once they are presented to the user. This architecture makes the Connect-Flash module perfect for transferring messages before redirecting the request to another page.

npm install --save connect-flash
npm install

Configuring Connect-Flash module

We have to configure the express.js file to use the flash module, we have to use require a method to include flash module and app.use() to register to our application. To do so, make the following changes in your config/express.js file:

..
.....
const flash = require('connect-flash');
...
...
app.use(flash());

Just to show the code, as we have already added to the code in step 2 in config/express.js file.

Using Connect-Flash module

Once installed, the Connect-Flash module exposes the req.flash() method, which allows you to create and retrieve flash messages. To understand it better, let’s observe the changes you’ve made to your Users controller. To understan it better at step 6, we have code renderSignup() and renderSignin() methods, which are responsible for rendering the sign-in and signup pages:

.......
messages: req.flash('error') || req.flash('info')
....
....
messages: req.flash('error')

These flash code we already added in our Step 6, Modifying the Users controller. The messages variable uses req.flash() to read the messages written to the flash. Now if you go over the signup() method, you’ll notice the following line of code:
req.flash(‘error’, message);
This is how error messages are written to the flash, again using the req.flash() method. After you learned how to use the Connect-Flash module, you might have noticed that we’re lacking a signin() method. This is because Passport provides you with an authentication method, which you can use directly in your routing definition.

Step 8: Adding routing code

Once you have your model, controller, and views configured, all that is left to do is define the user’s
routes. Add the following code in app/routes/users.server.routes.js  

const users = require('../../app/controllers/users.server.controller');
const passport = require('passport');

module.exports = function(app) {
    app.route('/signup')
    .get(users.renderSignup)
    .post(users.signup);
    app.route('/signin')
    .get(users.renderSignin)
    .post(passport.authenticate('local', {
        successRedirect: '/',
        failureRedirect: '/signin',
        failureFlash: true
    }));
    app.get('/signout', users.signout);
};

Most of the code can be self explanatory, we have to note special on POST request made to the /signin path using the passport.authenticate() method. When the passport.authenticate() method is executed, it will try to authenticate the user request using the strategy defined by its first argument. In this case, it will try to authenticate the request using the local strategy. The second parameter this method accepts is an options object, which contains three properties:

  1. successRedirect: This property tells Passport where to redirect the request once it successfully authenticated the user.
  2. failureRedirect: This property tells Passport where to redirect the request once it failed to authenticate the user
  3. failureFlash: This property tells Passport whether or not to use flash messages

Add the second routing code in app/routes/index.server.routes.js

// Load the 'index' controller
const index = require('../controllers/index.server.controller');

// Define the routes module' method
module.exports = function(app) {
	// Mount the 'index' controller's 'render' method
	app.get('/', index.render);
};

 

We also have to add code in app/controllers/index.server.controller.js 

exports.render = function(req, res) {
    res.render('index', {
        title: 'Hello World',
        userFullName: req.user ? req.user.fullName : ''
    });
};

 

Step 9: Adding view code for index, app/views/index.ejs

<!DOCTYPE html>
<html>
<head>
	<!-- Use the 'title' property to render a page title  -->

	<title><%= title %></title>
</head>
<body>
	<!-- If a user is authenticated, display the user's full name , otherwise display the authentication links -->

	<% if ( userFullName ) { %>
		<h2>Hello <%=userFullName%> </h2> 
		<a href="/signout">Sign out</a>
	<% } else { %>
		<a href="/signup">Signup</a>
		<a href="/signin">Signin</a>
	<% } %>
	<br>

	<!-- Load the static image file  -->

	<img src="img/logo.png" alt="Logo">
</body>
</html>

 

Step 10: Add the following code of configuration, we can add this code from starting of view, routes code.

Add code in config/env/development.js 

// Set the 'development' environment configuration object
module.exports = {
	db: 'mongodb://localhost/mean-development',
	sessionSecret: 'developmentSessionSecret'
};

config/env/production.js 

// Set the 'production' environment configuration object
module.exports = {
	db: 'mongodb://localhost/mean-production',
	sessionSecret: 'productionSessionSecret',
	facebook: {
		clientID: 'Facebook Application ID',
		clientSecret: 'Facebook Application Secret',
		callbackURL: 'http://localhost:3000/oauth/facebook/callback'
	},
	twitter: {
		clientID: 'Twitter Application ID',
		clientSecret: 'Twitter Application Secret',
		callbackURL: 'http://localhost:3000/oauth/twitter/callback'
	},
	google: {
		clientID: 'Google Application ID',
		clientSecret: 'Google Application Secret',
		callbackURL: 'http://localhost:3000/oauth/google/callback'
	}
};

 

config/config.js  

// Load the correct configuration file according to the 'NODE_ENV' variable
module.exports = require('./env/' + process.env.NODE_ENV + '.js');

 

config/mongoose.js 

// Load the module dependencies
const config = require('./config');
const mongoose = require('mongoose');

// Define the Mongoose configuration method
module.exports = function() {
	// Use Mongoose to connect to MongoDB
	const db = mongoose.connect(config.db);

	// Load the 'User' model 
	require('../app/models/user.server.model');

	// Return the Mongoose connection instance
	return db;
};

 

Express – Tutorials

  1. Express Js Introduction
  2. Express middleware
  3. Express Routing
  4. API in Express
  5. Serving static file in Express
  6. Local Login strategy
  7. Introducing Mongoose
  8. Managing Local User Authentication and Access Control
  9. Express OAuth strategies Login for Facebook

Express Project:

  1. Express apps to retrieve speaker information from data file
  2. Feedback form in the Express
  3. Creating a Simple Live Chat in Express

Managing Local User Authentication and Access Control

The user authentication is one of the most important tasks, we need to use authentication in most of our project. Passport is a robust piece of Node.js authentication middleware that helps us to authenticate and access control our Express apps. The Passport middleware allows developers
to offer various authentication methods using a mechanism called strategies, which allows you to
implement a complex authentication layer while keeping your code clean and simple.

The Passport middleware or passport.js allow us to define different strategy. Passport uses strategies to utilize both local authentication and OAuth authentication providers, such as Facebook, Twitter, and Google. Using Passport strategies,
you’ll be able to seamlessly offer different authentication options to your users while maintaining a
unified User model.

What are we learning?

  1. Integrating passport Js in our apps.
  2. Using both local and OAuth authentication strategy.
  3. Understand the serialization to maintains the session.
  4. Integrating Password the Bcrypt

USING PASSPORT’S LOCAL STRATEGY
First, we will learn the passport-local strategy and will learn OAuth authentication later.

Step 1: Installing our project, as we have a lot of dependencies and is better to type all dependency once in the package.JSON and install all together.
npm init Type all the dependency directly in the package.JSON and use npm install. Add the following code in package.JSON and add the line number 8 code also.

{
  "name": "passportlogin",
  "version": "1.0.0",
  "description": "User authentication app",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node app"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express":"*",
    "body-parser":"*",
    "express-handlebars":"*",
    "express-messages":"*",
    "express-session":"*",
    "express-validator":"*",
    "connect-flash":"*",
    "mongoose":"*",
    "passport":"*",
    "passport-http":"*",
    "passport-local":"*",
    "bcryptjs":"*"
  }
}

Step 2: We will create login register functionality first, we will make the user interface through bootstrap later. Inside the views/register.handlebars add the following code for login, registration form. When we fail to login successful, then express validator will display an error message and on successful login, we will display success message at the console.

<form method="post" action="/register">
  <div>
    <label>Name</label>
    <input type="text" name="name" placeholder="Name">
  </div>
  <div>
    <label>Username</label>
    <input type="text" name="username" placeholder="Username">
  </div>
  <div>
    <label>Email</label>
    <input type="email" name="email" placeholder="Email">
  </div>
  <div>
    <label>Password</label>
    <input type="text" name="password" placeholder="Password">
  </div>
  <div>
    <label>Confirm Password</label>
    <input type="text" name="password2" placeholder="Confirm Password">
  </div>
  <button type="submit">Register</button>
  <br>
  Have An Account? <a href="/">Login Now</a>
</form>

Step 3: We have to add code for routes to /register of registration and apply the express validator in routes/index.js as

var express = require('express');
var router = express.Router();

// Home Page
router.get('/', (req, res, next) => {
  res.render('index');
});

// Register Form

router.get('/register', (req, res, next) => {
  res.render('register');
});

// Process Register
router.post('/register', (req, res, next) => {
  const name = req.body.name;
  const username = req.body.username;
  const email = req.body.email;
  const password = req.body.password;
  const password2 = req.body.password2;

  req.checkBody('name', 'Name field is required').notEmpty();
	req.checkBody('email', 'Email field is required').notEmpty();
	req.checkBody('email', 'Email must be a valid email address').isEmail();
	req.checkBody('username', 'Username field is required').notEmpty();
	req.checkBody('password', 'Password field is required').notEmpty();
	req.checkBody('password2', 'Passwords do not match').equals(req.body.password);

  let errors = req.validationErrors();

  if(errors){
    res.render('register', {
      errors: errors
    });
  } else {
    console.log('SUCCESS');
    return;
  }
});

module.exports = router;

Step 4: Creating user model, in root folder add models/user.js and add the following code in user.js, Here we are exporting new model name called User and we are adding hash or encryption of Bcrypt to our password with the salt of 10 characters.

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/passportapp');
const bcrypt = require('bcryptjs');

// User Schema
const UserSchema = mongoose.Schema({
  name: {
    type: String
  },
  username: {
    type: String
  },
  email: {
    type: String
  },
  password: {
    type: String
  }
});

const User = module.exports = mongoose.model('User', UserSchema);

module.exports.registerUser = function(newUser, callback){
  bcrypt.genSalt(10, (err, salt) => {
    bcrypt.hash(newUser.password, salt, (err, hash) => {
      if(err){
        console.log(err);
      }
      newUser.password = hash;
      newUser.save(callback);
    });
  });
}

Step 5: In the index.js in routes, we will adding two new code
1. Add let User = require(‘../models/user’); at line number 3 of routes/index.js
2. Replace the code of console.log(success) of route.post(‘/register’,   to new code for the creating new user,  add route code for login page and once the successful new user is created then we will redirect to /login page.

// Login Form
router.get('/login', (req, res, next) => {
  res.render('login');
});

// Process Register
router.post('/register', (req, res, next) => {
  const name = req.body.name;
  const username = req.body.username;
  const email = req.body.email;
  const password = req.body.password;
  const password2 = req.body.password2;

  req.checkBody('name', 'Name field is required').notEmpty();
	req.checkBody('email', 'Email field is required').notEmpty();
	req.checkBody('email', 'Email must be a valid email address').isEmail();
	req.checkBody('username', 'Username field is required').notEmpty();
	req.checkBody('password', 'Password field is required').notEmpty();
	req.checkBody('password2', 'Passwords do not match').equals(req.body.password);

  let errors = req.validationErrors();

  if(errors){
    res.render('register', {
      errors: errors
    });
  } else {
    const newUser = new User({
      name: name,
      username: username,
      email: email,
      password: password
    });

    User.registerUser(newUser, (err, user) => {
      if(err) throw err;
      req.flash('success_msg', 'You are registered and can log in');
      res.redirect('/login');
    });
  }
});

module.exports = router;

 

Step 5: Inside the views, folder adds a new file login.handlebars with code LOGIN for testing only, when successful adding of new user will redirect to login page. Add new user test as a new user on localhost:3000/register. Check local MongoDB database for a new user as we didn’t create any mongo database, it will create automatically. Check local MongoDB database for a new user as we didn’t create any mongo database, it will create automatically. Check in local mongo shell >show dbs , > use passportapp >> show collection >> db.users.find().pretty()

We can see new user information on the local database.

Note: If we are using handlebar as a template, the middleware Express messages in app.js didn’t work because we can’t write Javascript within the handlebar. So we have to write the code different from the usual and will create the different message for each variable. In the app.js replace express message of

// Express messages
app.use(require('connect-flash')());
app.use((req, res, next) => {
  res.locals.messages = require('express-messages')(req, res);
  next();
});

Replace with new code as

// Express messages
app.use(flash());
app.use((req, res, next) => {
  res.locals.success_msg = req.flash('success_msg');
  res.locals.error_msg = req.flash('error_msg');
  next();
});

 

Step 6: We will add the code for express messages middleware in views/layouts/main.handlerbars to display any message like when login didn’t work.  As we have two type of errors message, one with highlight is from express messages middleware and other without the highlighted is the from the express validator for form. 

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Passport App</title>
    <link rel="stylesheet" href="/css/style.css">
  </head>
  <body>
    {{#if success_msg}}
      <div class="alert alert-success">{{success_msg}}</div>
    {{/if}}
    {{#if error_msg}}
      <div class="alert alert-danger">{{error_msg}}</div>
    {{/if}}
    {{#if errors}}
      {{#each errors}}
        <div class="alert alert-danger">{{msg}}</div>
      {{/each}}
    {{/if}}
    {{{body}}}
  </body>
</html>

Step 7: Inside the routes/index.js we will replace the code of process register for a new user to the new code and all other code are same.

var express = require('express');
var router = express.Router();

let User = require('../models/user');

// Home Page
router.get('/', (req, res, next) => {
  res.render('index');
});

// Login Form
router.get('/login', (req, res, next) => {
  res.render('login');
});

// Register Form
router.get('/register', (req, res, next) => {
  res.render('register');
});

// Process Register
router.post('/register', (req, res, next) => {
  const name = req.body.name;
  const username = req.body.username;
  const email = req.body.email;
  const password = req.body.password;
  const password2 = req.body.password2;

  req.checkBody('name', 'Name field is required').notEmpty();
	req.checkBody('email', 'Email field is required').notEmpty();
	req.checkBody('email', 'Email must be a valid email address').isEmail();
	req.checkBody('username', 'Username field is required').notEmpty();
	req.checkBody('password', 'Password field is required').notEmpty();
	req.checkBody('password2', 'Passwords do not match').equals(req.body.password);

  let errors = req.validationErrors();

  if(errors){
    res.render('register', {
      errors: errors
    });
  } else {
    const newUser = new User({
      name: name,
      username: username,
      email: email,
      password: password
    });

    User.registerUser(newUser, (err, user) => {
      if(err) throw err;
      req.flash('success_msg', 'You are registered and can log in');
      res.redirect('/login');
    });
  }
});

module.exports = router;

Step 8: We are able to create a new user or register for new user from above step, now we are adding login form and applying the local strategy. Add the following code for login in views/login.handlebars 

<form method="post" action="/login">
  <div>
    <label>Username</label>
    <input type="text" name="username" placeholder="Username">
  </div>
  <div>
    <label>Password</label>
    <input type="text" name="password" placeholder="Password">
  </div>
  <button type="submit">Login</button>
  <br>
  Don't Have An Account? <a href="/register">Register</a>
</form>

In views/register.handlebars we replace all one code from

Have An Account? <a href="/">Login Now</a>
To
Have An Account? <a href="/login">Login Now</a>

We have to add code for the login post and local strategy, inside routes/index.js. We will add the following code at two place

  1. At the top of routes/index.js
    const express = require('express');
    const router = express.Router();
    const passport = require('passport');
    const LocalStrategy = require('passport-local').Strategy;
  2. at the end or before module.exports = router;
// Local Strategy
passport.use(new LocalStrategy((username, password, done) => {
  User.getUserByUsername(username, (err, user) => {
    if(err) throw err;
    if(!user){
      return done(null, false, {message: 'No user found'});
    }

    User.comparePassword(password, user.password, (err, isMatch) => {
      if(err) throw err;
      if(isMatch){
        return done(null, user);
      } else {
        return done(null, false, {message: 'Wrong Password'});
      }
    });
  });
}));

passport.serializeUser((user, done) => {
  done(null, user.id);
});

passport.deserializeUser((id, done) => {
  User.getUserById(id, (err, user) => {
    done(err, user);
  });
});

// Login Processing
router.post('/login', (req, res, next) => {
  passport.authenticate('local', {
    successRedirect:'/',
    failureRedirect:'/login',
    failureFlash: true
  }, (req, res) => {
    res.redirect('/');
  });
});

module.exports = router;

Here we are defining what we will redirect if successful/ unsuccessful login, here in our case we will redirect to a home page on successful user login. On the above code of highlight, we have to define the corresponding function in our model user.

Now we will define login functionality, we will define the highlight function at the end in the models/user.js.

module.exports.getUserByUsername = function(username, callback){
  const query = {username: username}
  User.findOne(query, callback);
}

module.exports.getUserById = function(id, callback){
  User.findById(id, callback);
}

module.exports.comparePassword = function(candidatePassword, hash, callback){
  bcrypt.compare(candidatePassword, hash, (err, isMatch) => {
    if(err) throw err;
    callback(null, isMatch);
  });
}

In app.js we have to add two line of code for password middleware and at below the express session middleware in app.js. 

const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const exphbs = require('express-handlebars');
const expressValidator = require('express-validator');
const flash = require('connect-flash');
const session = require('express-session');
const passport = require('passport');
const mongoose = require('mongoose');

const app = express();
const port = 3000;

const index = require('./routes/index');

// View Engine
app.engine('handlebars', exphbs({defaultLayout:'main'}));
app.set('view engine', 'handlebars');

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

// Body Parser Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

// Express Session
app.use(session({
    secret: 'secret',
    saveUninitialized: true,
    resave: true
}));

// Init passport
app.use(passport.initialize());
app.use(passport.session());

// Express messages
app.use(flash());
app.use((req, res, next) => {
  res.locals.success_msg = req.flash('success_msg');
  res.locals.error_msg = req.flash('error_msg');
  next();
});


// Express Validator
app.use(expressValidator({
  errorFormatter: (param, msg, value) => {
      let namespace = param.split('.')
      , root    = namespace.shift()
      , formParam = root;

    while(namespace.length) {
      formParam += '[' + namespace.shift() + ']';
    }
    return {
      param : formParam,
      msg   : msg,
      value : value
    };
  }
}));

app.use('/', index);

// Start Server
app.listen(port, () => {
  console.log('Server started on port '+port);
});

We will define the flash message as a global variable in app.js to displaying the message of login success or fail in views/layouts/main.handlerbar. Append the highlighted code on express message in app.js

// Express messages
app.use(flash());
app.use((req, res, next) => {
  res.locals.success_msg = req.flash('success_msg');
  res.locals.error_msg = req.flash('error_msg');
  res.locals.error = req.flash('error');
  res.locals.user = req.user || null;
  next();
});

In the views/layout/main.handlebars append highlight code on existing code.

!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Passport App</title>
    <link rel="stylesheet" href="/css/style.css">
  </head>
  <body>
<!-- New user registeration msg -->
    {{#if success_msg}}
      <div class="alert alert-success">{{success_msg}}</div>
    {{/if}}
    {{#if error_msg}}
      <div class="alert alert-danger">{{error_msg}}</div>
    {{/if}}
<!-- For login success or failure msg -->
    {{#if error}}
      <div class="alert alert-danger">{{error}}</div>
<!-- Form validation msg -->
    {{/if}}
    {{#if errors}}
      {{#each errors}}
        <div class="alert alert-danger">{{msg}}</div>
      {{/each}}
    {{/if}}
    {{{body}}}
  </body>
</html>

Note: Successful login will take you to root or home page.

Step 9: We have to add logout code and access control on login. First, we will add logout code in routes/index.js after Register form code.

// Register Form
......
// Logout
router.get('/logout', (req, res, next) => {
  req.logout();
  req.flash('success_msg', 'You are logged out');
  res.redirect('/login');
});

Test log out in URL, the first login with validate user login and then type localhost:3000/logout will redirect to the login page with the message as below. 

Now we will apply the access control on login, as for above code till now we can access the home page directly without login. We can control the access as two step

  1. Add the following code at the end of routes/index.js
// Access Control
function ensureAuthenticated(req, res, next){
  if(req.isAuthenticated()){
    return next();
  } else {
    req.flash('error_msg', 'You are not authorized to view that page');
    res.redirect('/login');
  }
}

module.exports = router;

2. Apply the access control on the dashboard or home page. Edit the code of home in routes/index.js


// Home Page
router.get('/', (req, res, next) => {
  res.render('index');
});

To new code as

// Home Page - Dashboard
router.get('/', ensureAuthenticated, (req, res, next) => {
  res.render('index');
});

We will get message while access the dashboard or home page as 

 

Step 10: Now we will apply the user interface through bootstrap, as

We will add the nav bar code from bootstrap example theme, and bootstrap theme link from bootswatch.com Flatly theme copy it URL and the past in views/layouts/main.handlebars

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Passport App</title>
    <link rel="stylesheet" href="https://bootswatch.com/flatly/bootstrap.min.css">
    <link rel="stylesheet" href="/css/style.css"> 
  </head>
  <body>
    
    <nav class="navbar navbar-inverse">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Passport App</a>
        </div>
        <div id="navbar" class="collapse navbar-collapse">
          <ul class="nav navbar-nav navbar-left">
            <li><a href="/">Dashboard</a></li>
          </ul>

          <ul class="nav navbar-nav navbar-right">
            {{#if user}}
              <li><a href="/logout">Logout</a></li>
            {{else}}
              <li><a href="/login">Login</a></li>
              <li><a href="/register">Register</a></li>
            {{/if}}
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </nav>
  <div class="container">
    {{#if success_msg}}
      <div class="alert alert-success">{{success_msg}}</div>
    {{/if}}
    {{#if error_msg}}
      <div class="alert alert-danger">{{error_msg}}</div>
    {{/if}}
    {{#if error}}
      <div class="alert alert-danger">{{error}}</div>
    {{/if}}
    {{#if errors}}
      {{#each errors}}
        <div class="alert alert-danger">{{msg}}</div>
      {{/each}}
    {{/if}}
    {{{body}}}
  </div>
  </body>
</html>

Apply the div container class on error message as in highlight code above. As we can easily access the user variable anywhere, which defines global in app.js add the following code in views/index.handlerbars or dashboard as

<h1>Dashboard</h1>
<p>Welcome {{user.name}}</p>

Last, apply the bootstrap class in views/login.handlebars and register.handlebars. First, we will apply bootstrap class on login view as

<form method="post" action="/login">
  <div class="form-group">
    <label>Username</label>
    <input class="form-control" type="text" name="username" placeholder="Username">
  </div>
  <div class="form-group">
    <label>Password</label>
    <input class="form-control" type="password" name="password" placeholder="Password">
  </div>
  <button class="btn btn-primary" type="submit">Login</button>
  <br>
  Don't Have An Account? <a class="btn btn-default btn-sm" href="/register">Register</a>
</form>

and also apply to register view as

<form method="post" action="/register">
  <div class="form-group">
    <label>Name</label>
    <input class="form-control" type="text" name="name" placeholder="Name">
  </div>
  <div class="form-group">
    <label>Username</label>
    <input class="form-control" type="text" name="username" placeholder="Username">
  </div>
  <div class="form-group">
    <label>Email</label>
    <input class="form-control" type="email" name="email" placeholder="Email">
  </div>
  <div class="form-group">
    <label>Password</label>
    <input class="form-control" type="text" name="password" placeholder="Password">
  </div>
  <div class="form-group">
    <label>Confirm Password</label>
    <input class="form-control" type="text" name="password2" placeholder="Confirm Password">
  </div>
  <button class="btn btn-primary"type="submit">Register</button>
  <br>
  Have An Account? <a class="btn btn-default btn-sm" href="/login">Login Now</a>
</form>

 

 

Serving static file in Express

We can use Express’s built-in middleware called static to serve static file like images, CSS files, and JavaScript file to the client. First, we have to define the directory where will put all are the static file to the middleware function express.static to start serving the files directly. We will define public as a directory for serving the static file. We can reach our static file in the browser as example
http://localhost:3000/images/photo1.png

var express = require('express');
var app = express();
app.use(express.static('app/public'));

Here we don’t have to require the path module, as we are run the node app in the same folder as the path. If we are put the static directory in another folder, then it is safer to use an absolute path of the directory that you want to serve. Then we will change our code as

var express = require('express');
var path = require('path');
var app = express();

var filePath = path.join(__dirname, "public");
app.use(express.static(filePath));

app.use(function(req, res){
    console.log("Request IP", + req.url);
    console.log("Request data: " + new Date());
    
    res.status(404);
    res.send("File not found");
});

 

API in Express

An application program interface [API] is code that allows two software programs to communicate with each other. That makes it possible for applications to share data and take actions on one another’s behalf without requiring developers to share all of their software’s code.

In the simplest terms, APIs are sets of requirements that govern how one application can talk to another.
APIs do all this by “exposing” some of a program’s internal functions to the outside world in a limited fashion.

In simple term, API’s are the ways to one piece of code to communicate with other code regardless of distance.

We will build a simple API that will generate an even number between two range.  While requests the API we must send a minimum and maximum range for an even number as http://localhost:3000/even/10/20. Where  10 and 20 are a minimum and maximum range where we will be generating the even numbers. Our web app will parse those range from requested URL and will generate the range in an array even and send it back to the client with array object as in JSON format.

 

Introduction to Routing

 

Express has some built-in the service layer, express handle the service requests using routing. The routing in Express maps HTTP verbs plus URI combo to an ask for the handler function. The routes are the application endpoint URI or path and HTTP request method (GET, POST, HEAD, PUT, DELETE ) and how the endpoint responds to a client request. In the example below, we displaying the different message with routing to specific URL in express.

 

var express = require("express")
var app = express();

app.get("/", function(req, res){
	res.send("Welcome to Home page");
});

app.get("/tamo", function(req, res){
	res.send("Welcome to tamo page");
});

app.use(function(req, res){
	res.status(404).send("Page not found");
});

app.listen(3000)

 

When we make professional node apps, then we have to use standard routing. We will create the separate folder for the routes, views and static files as public in the app folder. All the route code kept in routes folder.  Example index.js for the home page route and feedback .js for feedback page route.

Step1: Add the following code in app/app.js and we will have to add the corresponding view for the home page.

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

app.set('port', process.env.PORT || 3000); 
app.set('view engine', 'ejs');
app.set('views', 'app/views');


app.use(express.static('app/public'));
app.use(require('./routes/index'));
app.use(require('./routes/teachers'));
;

var server = app.listen(app.get('port'), function(){
    console.log('Listening on port' + app.get('port'));
});

reload(server, app);

 

Add the following code in app/routes/index.js to route to a home page and we will have to create the corresponding view for the home page.

var express = require('express');
var router = express.Router();

router.get('/', function(req, res){
    res.render('index',{
        pageTitle: 'Home',
        pageID: 'home'
    });
});

module.exports = router; 

Add the following code in app/routes/teacher.js to route to URL localhost/teacher and /teacher/id and we will have to create the corresponding view for both teachers and teacher/id route. Express allows us to specify our routes as a string and to specify them as regular expressions.

var express = require('express');
var router = express.Router();


var ALLOWED_IPS = [
    "127.0.0.1",
    "10.10.10.1",
    "localhost"
];

router.use(function(req, res, next){
    var userIsAllowed = ALLOWED_IPS.indexOf(req.ip) !== -1;
    if(!userIsAllowed){
        res.status(401).send("Not Authorized !");
    }else{
        nex();
    }
});


router.get('/teachers', function(req, res) {
  res.render('teachers', {
    pageTitle: 'Teachers',
    pageID: 'teacherList'
  });
});

router.get('/teachers/:teacherid', function(req, res) {
  data.speakers.forEach(function(item) {
    if (item.shortname == req.params.speakerid) {
      pageSpeakers.push(item);
      pagePhotos = pagePhotos.concat(item.artwork);
    }
  });

  res.render('teachers', {
    pageTitle: 'Teacher Info',
    pageID: 'teacherDetail'
  });
});

router.get('/teacher/message', function(req, res) {
  res.render('users', {
    pageTitle: 'message',
    pageID: 'messageDetail'
  });
});
module.exports = router;

Using Express with HTTPS

We can add the https to our Node apps. The express use built-in HTTPS module for HTTPS access and we have to supply certification key and the private key in Node to access our web HTTPS protocol. Simple example node apps with both HTTP and HTTPS

Example: Express apps with both HTTP and HTTPS

var https = require("https");
var fs = require("fs");

var app = express();

var httpsOptions = {
	key: fs.readFileSync("path/to/private/key.pem");
	cert: fs.readFileSync("path/to/certificate.pem")
};
http.createServer(app).listen(80);
https.createServer(httpsOptions, app).listen(443);