Unit 3
Unit 3
Unit 3
Unit-III
Node.js: Introduction, Advantages, Node.js Process Model, Node JS Modules.Express.js:
Introduction to Express Framework, Introduction to Nodejs , What isNodejs, Getting
Started with Express, Your first Express App, Express Routing,Implementing MVC in
Express, Middleware, Using Template Engines, ErrorHandling , API Handling ,
Debugging, Developing Template Engines, Using ProcessManagers, Security &
Deployment.
Node.JS: Introduction:
Why and What Node.js: Let us look at the below scenarios for understanding the need for Node.js:
Scenario 1: JavaScript has been the most used language for creating dynamic web pages. Its rising
popularity has brought in a lot of changes. JavaScript has moved to the server-side too, establishing
itself on the web servers as well. That entailed a capability to generate web pages on the server. Node.js
was the first legitimate attempt to bring JavaScript to the server-side thereby making it possible to run
JavaScript outside the web browser. Node.js also represents the "JavaScript everywhere" paradigm, by
unifying web application development around a single language, rather than using different languages
for server-side and client-side.
Scenario 2: Consider a scenario where you are trying to upload videos to a social media website. You
may observe that lot of time is taken for getting your request processed. This may be because the
preceding requests need to be completed first by the web server of the application before executing this
new request. In order to ensure the requests get served concurrently, multiple approaches have been
proposed. This is where Node.js comes in. Since Node.js uses an event looping mechanism, a Node.js
web server is capable of sending responses in a non-blocking way. This eventually means, a Node.js
server can handle a large number of requests than the commonly used traditional web servers.
Let us have a look at the nature of Node.js and some of the benefits associated with Node.js:
1. Node is popular: Node.js is one of the most popular platforms for application development as it uses
JavaScript. JavaScript is a powerful programming language as it provides good flexibility to developers.
2. Full-stack JavaScript development: Node.js has paved the way for JavaScript to be on the server-side
as well. Hence applications can now have both back-end and front-end developed with the same
JavaScript language. We now have two popular JavaScript software stacks for building full stack web
applications: MEAN and MERN.Node is the N in the MEAN stack. In this stack, Node is used along with
the MongoDB database and Express, which is a Node framework for back-end application development.
Angular framework is used for front-end application development.Node is the N in the MERN stack as
well. Here, Node is used along with MongoDB database and Express for back-end application
development. React is used for front-end application development in this stack.
2
3. Very fast: Node applications have better performance than applications developed using other
technologies due to the JavaScript engine used internally in Node. The engine converts JavaScript code
into machine code and provides extremely fast execution.
4. Node is powerful: Node uses a non-blocking I/O model and asynchronous programming paradigm,
which helps in processing requests in a non-blocking way.
5. Data Streaming: Node has a built-in Streams API that helps in creating applications where data
streaming is required.
6. Rich Ecosystem: Node.js provides a package manager called NPM (Node Package Manager) which is
the world's largest software registry that helps open source developers to share and use packages using
NPM.
7. Modularity: Node applications can be developed as modules which helps in dividing the application
into a reusable set of code.
8. Wide client-side and database connectivity: Node.js has absolutely no dependencies and also goes
perfectly with any possible client-side technologies like Angular, React, etc., and any database like
MySQL or MongoDB.
All these organizations were using different technologies like Java, Rails, etc. for developing the server-
side of their applications. But later, they migrated to Node.js because of the features provided by it.
The below table lists the reasons why they migrated to Node.js.
3
What is Node.js?
Node.js is an open-source JavaScript run-time environment used for building scalable network
applications. It helps in developing the server-side of the application using JavaScript language. It is used
for building data-intensive real-time applications.
4. REST APIs
Let us understand the features of Node.js which makes it the most popular platform for server-side
application development.
1. V8 engine
As application development in Node uses JavaScript language, the Node.js platform needs an engine for
executing JavaScript. The engine used in the platform is V8 which is an open-source high-performance
engine. It is developed by Google and written in C++. V8 compiles JavaScript source code into native
machine code. The same engine is used in the Google Chrome browser as well to execute JavaScript
code. The performance of the Node.js application is faster due to this ultra-fast engine used in the
platform.
2. Single codebase
Since coding in Node is based on JavaScript, both the client and the server-side code can be written
using the same JavaScript language. It allows the front-end and back-end teams to be combined into a
single unit. Also since Node.js uses JavaScript, we can quickly manipulate the JSON data retrieved from
external web API sources like MongoDB, hence reducing the processing time needed per request.
All the APIs in Node are asynchronous i.e. non-blocking, which means Node-based server will never wait
for an API to return data or to complete the request, it will move to the next request process. The
notification mechanism of Node.js helps in getting the response from the previous requests after its
completion.
Consider the scenario where we need to read the content of a file and then database
operation is to be executed. When the file read operation is started, the rest of the code in the program
gets blocked until the file reading operation is finished. Once the file reading is done, then it continues
to execute the remaining code. Though the database operation code is not dependent on the file read
operation, it is getting blocked. This kind of code is considered as blocking code or synchronous code.
Consider the same scenario of reading a file and then database operation is to be executed.
On asynchronously implementing this, when the file read operation is started, it will not wait for the
read operation to complete, it will just continue execution of the rest of the code. Once the file reading
is done, it will be informed and the corresponding function gets called. This provides a non-blocking way
of executing the code.
1. setTimeout(() => {
2. console.log("after 20 seconds");
3. }, 20000);
In the above example, setTimeout() takes two arguments. The first argument is the callback function
and the second argument is the delay in milliseconds. The callback function is called after 20 seconds.
In Node.js, at the completion of each task, the respective callbacks written gets invoked. All the APIs of
Node.js are written in a way to support callbacks. This makes Node.js highly scalable as it can handle a
large number of requests in a non-blocking way.
Node.js is said to be highly scalable because it handles the client request using the Single-threaded
model with an event loop. Node environment follows the Single Threaded Event Loop Model which is
based on JavaScript's callback mechanism.
5
Let us take a look at the Single-threaded model with the event loop of Node.js.
Step 1: Assume 'n' number of clients, send requests to the webserver to access the web application
concurrently.
Node web server receives those requests and places them into a queue known as "Event Queue". The
Node web server internally maintains a limited thread pool to provide service to the client. Let us
assume that 'm' number of threads can be created and maintained.
Step 2: The Node web server internally has a component, known as "Event Loop". It uses the indefinite
loop to receive requests and process them. But the Event loop component uses a "Single Thread" to
process the requests.
Step 3: The event Loop component checks for any client request that is placed in the Event Queue. If
norequests are present, then it waits for incoming requests. If the requests are present, then it picks up
one client request from the Event Queue and starts processing that request.
Step 4: If that client request does not require any blocking I/O operations, then the request is processed
till completion and the response is sent back to the client.
Step 5.1: If the client request requires some blocking I/O operations like file operations, database
interactions, any external services then it checks the availability of threads from the internal thread
pool.
Step 5.2: One thread is assigned from the internal pool of threads and assigned to the client request.
That thread is responsible for taking that request, processing it, and performing blocking I/O operations.
6
Step 6: After processing the request, the response is prepared and sends back to the Event Loop. Event
Loop then sends that response back to the requested client.
5. Scalability
One of the reasons for the Node.js application scalability is that it makes use of event-driven
programming with the Single Threaded Event Loop Mechanism.
This enables the Node application to serve a huge number of incoming requests concurrently
and it scales up automatically to serve those requests efficiently.
Companies like eBay and Walmart makes use of Node.js to scale up their application to support
multiple external services and handle the requests flowing in with those services.
6. I/O bound operations
Due to its asynchronous/non-blocking nature, Node.js can be used to create I/O bound
applications that involve huge input-output operations, such as creating real-time applications
that have real-time data flowing in.
Applications like Facebook, online chat applications, and Twitter are a few examples. An online
marketing company like eBay makes use of Node.js to handle lots of I/O-bound operations to
handle eBay-specific services that display information on the page.
7. Streaming of data
Node.js can be used to create data streaming applications that involve streaming the data
quickly. Node.js has a built-in Stream API available using which we can stream the data very fast.
Applications like the Twitter stream, video stream, etc. use this feature.
Media companies like National Public Radio, Direct TV, HBO makes use of Node.js to stream the
data to their viewers.
8. Modularity
Node.js supports modular JavaScript. Instead of writing code in a single JavaScript file, the code
can be written in modules which can then be accessed at multiple places in the application.
This helps in easy maintenance and reusability of the code.
How to use Node.js:
Download Node.js from the official site. Follow the instructions mentioned on the site for
installing it on your machine.
It is important to download the stable version while installing, as the Node.js team keeps
upgrading the version by adding new features and enhancements.
To check whether Node.js is installed or not in your machine, open the Node command prompt
and check the Node.js version by typing the following command.
7
Node.js also provides a package manager called NPM(Node Package Manager) which is a collection of
all open-source JavaScript libraries. It helps in installing any library or module into your machine.
Thus we have successfully installed Node.js in the machine and we can start the application
development using Node.js.
Step 2: Navigate to the created NodeJS folder in the NodeJS command prompt and execute the
JavaScript file, first.js using the node command.
1. node first.js
Step 3: After the successful interpretation of the code, we can see the output in the Node.js command
prompt as shown below.
So, we can now conclude that any JavaScript file which doesn't contain codes for browser interactions
will execute successfully using the Node platform.
Step 1: Create a new JavaScript file httpserver.js and include the HTTP module.
1. const http = require("http");
Step 2: Use the createServer() method of the HTTP module to create a web server. var server =
http.createServer((req, res) => { res.write("Hello World! I have created my first server!"); res.end(); });
server.listen(3000);
console.log("Server started... Running on localhost:3000");
Step 3: Save the file and start the server using the node command. When the file executes successfully,
we can observe the following output in the console.
Introduction
Node.js is a JavaScript run-time environment built on Chrome's V8 engine, not a
framework or library. It enables server-side execution of JavaScript code.
When Node.js performs an I/O operation, like reading from the network, accessing a
database or the filesystem, instead of blocking the thread and wasting CPU cycles
waiting, Node.js will resume the operations when the response comes back.
This allows Node.js to handle thousands of concurrent connections with a single
server without introducing the burden of managing thread concurrency, which could
be a significant source of bugs.
10
Node.js has a unique advantage because millions of frontend developers that write
JavaScript for the browser are now able to write the server-side code in addition to the
client-side code without the need to learn a completely different language.
In Node.js the new ECMAScript standards can be used without problems, as you don't
have to wait for all your users to update their browsers - you are in charge of deciding
which ECMAScript version to use by changing the Node.js version, and you can also
enable specific experimental features by running Node.js with flags.
Why Node.JS?
Node.js is used to build back-end services like APIs like Web App, Mobile
App or Web Server. A Web Server will open a file on the server and return
the content to the client. It’s used in production by large companies such
as Paypal, Uber, Netflix, Walmart, and so on.
// Creating a server
const server = http.createServer((req, res) => {
// Setting the content type to HTML
res.writeHead(200, {
'Content-Type': 'text/html'
});
Code Explaination:
We use the http module to create an HTTP server.
The server listens on the specified port and hostname.
When a new request arrives, the callback function handles it by setting
the response status, headers, and content.
13
Node.js Advantages
Node.js Advantages include
1. High Performance
2. Scalability
3. Easy to Learn
4. Reduces Loading time using caching
5. Improves Response time and boosts performance
6. Large Community Support
7. Cost-Effective
8. Extensibility
15
High Performance
One of the most important features of node.js is the ability to create lightning-fast
apps that produce results in seconds.
The ability to multitask that Node.js provides is extremely beneficial to web apps.
Its event-driven, single-threaded design rapidly processes several simultaneous
requests without clogging the RAM. Additionally, its event-loop and non-blocking
I/O operations allow code to be executed at a rate that indirectly influences the
application's overall performance.
Node.js advantage is that it is powered by the V8 engine in Google Chrome,
written in C++. It rapidly and efficiently converts JavaScript to machine code.
This engine is significant because Google makes significant investments in
improving efficiency and security and providing strong support for sophisticated
JavaScript capabilities.
Furthermore, because it allows non-blocking I/O operations, the run-time
environment speeds up code execution.
Google released the V8 benchmark set to improve node.js performance with
faster execution, better compilers, security patchworks, and scalability.
Scalability
One of the Node.js advantages is that developers can easily grow applications in
both horizontal and vertical orientations.
The applications can be horizontally scaled by adding additional nodes to the
existing system.
16
Furthermore, during the vertical scaling of the application, Node.js allows you to add
extra resources to single nodes. As a result, it is extremely scalable and offers a
superior alternative to existing JavaScript servers.
Easy to Learn
Most frontend developers are familiar with JavaScript because it is one of the
most extensively used programming languages.
It will be lot easier for them to get started using Node.js on the backend. It is
simpler to understand Node.js, and working with it takes less time.
Cost-Effective
Node.js allows programmers to develop server-side JavaScript and frontend
JavaScript codes with simplicity.
One of the major node.js advantages is that it eliminates the need for two
resource teams, saving time, money, and energy for overall project development.
LinkedIn's development team switched from Ruby on Rails to Node.js, and the
benefits of Node.js helped them gain performance.
They lowered the number of servers from 30 to only three. They began
delegating and utilizing resources more effectively, changing their attention from
debugging to app development.
Extensibility
Node.js offers a lot of extensibility, which means it can be changed and improved
to fit unique requirements.
Data may be sent between the web server and the client using the JSON format.
It also has APIs for constructing HTTP, TCP, and DNS servers, among other
features.
Large Community Support
Millions of developers actively contribute to the Node.js community. To address
even the most bizarre development difficulties, anticipate widespread
cooperation from development specialists all across the world.
NPM is the world's most comprehensive package manager registry. It includes a
number of tools and libraries that you may use right away in your project.
Developers will also have access to a wide pool of resources on GitHub,
including ready–to–use solutions, scripts, modules, libraries, and registries
created by developers to help them do more with less.
IBM is a strong supporter of this rapidly evolving technology and has announced
plans to sponsor and speak at key Node events to expand the technology's reach
and use. They also want to create open authority in the Node.js and JS
Foundations merger, resulting in a strong and thriving JavaScript ecosystem.
Many big tech companies, including Amazon, Google, Facebook, and Netflix, contribute
significantly to the node.js community. They've made significant contributions in the
shape of several open-source projects. Acceptance by tech giants and the development
community ensures the presence and expansion of technology in the foreseeable
future.
Improves Response time and boosts performance
17
When Netflix used Java and JavaScript, the startup time was 40 minutes. They
then moved to node.js and succeeded in cutting the startup time to under 40
seconds.
A constant stream of queries impacts an app's response time and performance. If
your IT stack isn't ready to manage a high volume of requests, the value of your
product will rapidly dwindle.
The single-threaded event-loop approach in Node.js provides a non-blocking
asynchronous design.
This design uses fewer resources since it does not spawn more threads. It
improves the responsiveness of your application by dealing with several
concurrent users.
Reduces Loading Time using caching
The Node.js Caching module makes it simple for developers to decrease task
workload and code re-execution.
It is one of the major node.js advantages.
As a result, the initial module of the web application is cached in the in-app memory
each time it is accessed. A user may browse online sites quickly without having to wait
long.
Helps in building the cross-functional teams
You can use Node.js to construct cross-platform real-time web apps using
platforms like Electron and NW.js.
This eliminates the need to write separate code for different desktop versions
such as Windows, Linux, and macOS.
Your development team will be able to create native desktop apps in the future
without needing expert-level knowledge of Objective-C, C#, or any other
language.
Additionally, your Node.js engineers will have unlimited access to Google
Chrome Developer Tools to build, debug, and create code.
This powerful technique is used in web development using Javascript frameworks like
AnjularJS, Vue.js, and React for the frontend and Node.js for the backend. It has
enabled full-stack developers to take advantage of the benefits and opportunities that
node.js provides.
Node.js Disadvantages
Node.js Disadvantages include
1. Unstable API
2. Lack of Library Support
3. Asynchronous Programming Model
18
Unstable API
The Application Programming Interface changes frequently and is not reliable,
which is one of the most prevalent challenges that most developers experience.
Occasionally, a new API will come with several incompatible changes.
As a result, developers must update existing code bases to verify that they are
compatible with the latest Node.js API version.
Lack Of Library Support
In comparison to any other programming language, JavaScript lacks a well-
equipped and robust library system.
As a result, processes like Object-Relational Mapping (ORM), image processing,
database operations, and XML parsing must be performed via a common library.
This makes it difficult to use Node.js for even simple programming tasks.
Asynchronous Programming Model
If you want to make your apps more scalable, you'll need to use the
asynchronous programming strategy.
However, many engineers may find this programming method more difficult than
linear blocking I/O programming.
Another disadvantage of asynchronous programming is that the code tends to
become clunky, forcing programmers to rely on nested calls.
does not return to thread pool until it completes the execution and
returns a response.
Node.js provides the facility to get process information such as process id, architecture, platform,
version, release, uptime, upu usage etc. It can also be used to kill process, set uid, set groups,
unmask etc.
The process is a global object, an instance of EventEmitter, can be accessed from anywhere.
Property Description
platform returns platform of the process: 'darwin', 'freebsd', 'linux', 'sunos' or 'win32'
1. node process_example1.js
22
Let's see another process example to print command line arguments. Here node is
considered as the first argument, filename is considered as the second argument and
actual command line arguments are considered as third, fourth, fifth and so on.
File: process_example2.js
1. node process_example2.js
Function Description
hrtime() returns the current high-resolution real time in a [seconds, nanoseconds] array
File: process_example3.js
1. node process_example3.js
Process Events
The process object is an instance of EventEmitter and emits the
following events −
exit
1
Emitted when the process is about to exit. There is no way to prevent the exiting of the event
loop at this point, and once all exit listeners have finished running, the process will exit.
24
beforeExit
2 This event is emitted when node empties its event loop and has nothing else to schedule.
Normally, the node exits when there is no work scheduled, but a listener for 'beforeExit' can
make asynchronous calls, and cause the node to continue.
uncaughtException
3
Emitted when an exception bubbles all the way back to the event loop. If a listener is added for
this exception, the default action (which is to print a stack trace and exit) will not occur.
warning
4 The 'warning' event is emitted whenever Node.js emits a process warning. A process warning is
similar to an error in that it describes exceptional conditions that are being brought to the user's
attention.
5 Signal Events
Emitted when the processes receives a signal such as SIGINT, SIGHUP, etc.
Example
Output
This message is displayed first.
A beforeExit event occured with code: 0
Process exit event with code: 0
25
Example
process.on('exit', function(code) {
// Following code will never execute.
setTimeout(function() {
console.log("This will not run");
}, 0);
Output
Program Ended
About to exit with code: 0
Process Methods
abort()
Example
abortfunction();
Output
Start...
Hello World
Hello World
Hello World
Hello World
chdir()
cwd()
Example
console.log(`Starting directory: ${process.cwd()}`);
try {
process.chdir('NewNodeApp');
console.log(`New directory: ${process.cwd()}`);
27
} catch (err) {
console.error(`chdir: ${err}`);
}
Output
Starting directory: D:\nodejs
New directory: D:\nodejs\NewNodeApp
exit()
Example
console.log('Code running');
process.on('exit', function(code) {
return console.log(`exiting with the error code : ${code}`);
});
setTimeout((function() {
return process.exit(0); //after 5 sec
}), 5000);
Output
Code running
exiting with the error code : 0
kill()
kill(pid[, signal])
28
Parameters
pid : A process ID
Example
The following code obtains the pid of the current process. It waits
for a long enough duration before it exits normally. In between if
you emit SIGINT signal by pressing ctrl-C, the process doesn’t
terminate.
memoryUsage()
Example
console.log(process.memoryUsage());
29
Output
{
rss: 24768512,
heapTotal: 4079616,
heapUsed: 3153848,
external: 1097184,
arrayBuffers: 10519
}
nextTick()
nextTick(callback[, ...args])
Example
console.log('start');
process.nextTick(() => {
console.log('nextTick callback executed in next iteration');
});
console.log('scheduled');
Output
start
scheduled
nextTick callback executed in next iteration
Process properties
process.arch
30
The operating system CPU architecture for which the Node.js binary
was compiled.
'arm',
'arm64',
'ia32',
'loong64',
'mips',
'mipsel',
'ppc',
'ppc64',
'riscv64',
's390',
's390x',
'x64'
Example
console.log(`This processor architecture is ${process.arch}`);
Output
This processor architecture is x64
process.argv
Save the following script as hello.js and run it from command line,
pass a string argument to it from command line.
console.log(args);
31
console.log("Hello,", name);
process.env
Example
const processEnvKeys = Object.keys(process.env);
processEnvKeys.forEach((key) => {
console.log(`${key}: ${process.env[key]}`);
});
Output
SystemDrive: C:
SystemRoot: C:\WINDOWS
TEMP: C:\Users\mlath\AppData\Local\Temp
TMP: C:\Users\mlath\AppData\Local\Temp
USERDOMAIN: GNVBGL3
USERDOMAIN_ROAMINGPROFILE: GNVBGL3
USERNAME: mlath
USERPROFILE: C:\Users\mlath
windir: C:\WINDOWS
ZES_ENABLE_SYSMAN: 1
TERM_PROGRAM: vscode
TERM_PROGRAM_VERSION: 1.84.2
LANG: en_US.UTF-8
COLORTERM: truecolor
VSCODE_INJECTION: 1
32
VSCODE_NONCE: b8069509-e0f5-4bbd-aac9-fc448279b154
You can also set environment variables from the command line.
Assign the values to one or more variables before the node
executable name.
process.env.USER_ID; // "101"
process.env.USER_NAME; // "admin"
process.pid
Example
const { pid } = require('node:process');
process.platform
This property returns a string identifying the operating system.
'aix'
'darwin'
'freebsd'
'linux'
'openbsd'
'sunos'
'win32'
33
process.version
Example
console.log(`Version: ${process.version}`);
Output
Version: v20.9.0
What are Modules in Node.js ?
In Node.js Application, a Module can be considered as a block of code that
provide a simple or complex functionality that can communicate with external
application. Modules can be organized in a single file or a collection of
multiple files/folders. Almost all programmers prefer modules because of
their reusability throughout the application and ability to reduce the
complexity of code into smaller pieces.
Nodejs uses the CommonJS Module standard implementation in its module
ecosystem.
Types of Modules: In Nodejs, there is 3 type of modules namely
Core Modules
Local Modules
Third-Party Modules
Core Modules: Node.js comes with dozens of built-in modules. These built-
in modules are sometimes referred to as core modules. The module system
is built around the require function. This function is used to load a module
and get access to its contents. require is a global variable provided to all
your Node.js scripts, so you can use it anywhere you like. require() function
will return a JavaScript type depending on your module.
Syntax for Importing Module:
const module = require("Name_of_Module_to_be_imported");
How to use Core Module: You can directly use the Nodejs core module in
your application without any installation. Let’s see an example of the file
system (fs) module to handle the files in the application.
Initially, the Project Directory will look like this:
34
The script above uses require to load in the fs module. This is a built-in
Node.js module that provides functions you can use to manipulate the file
system. The script uses writeFileSync to write a message to notes.txt.
To run the script use the following command on your terminal
$ node index.js
After you run the script, you’ll notice a new notes.txt file in your directory.
Open it up and you’ll see, “I love to code”.
Output: Now we have a new file notes.txt in our directory. And “I love to
code” written has written on it.
Output
Local Modules: Putting all your code in a single file is not a good idea. As
you add more code, you’ll want to stay organized and break your Node.js
app into multiple scripts that all work together. For that purpose, we can
create local modules in our application.
Exporting from files: Firstly we need to create a file called utils.js. Now We
can export javascript code written on this file using module.exports. In below
a function is defined and assigned to the module.exports.
Project setup:
36
module.exports = tests;
Importing your own files: Now we need to import the local file
into index.js. require function is also used for importing the files in the
directory. All you need to do is provide require with a relative path to the
script you want to load. This path should start with ./ and then link to the file
that needs to be loaded.
Filename:- In the index.js file
Javascript
utility();
37
The code above uses require to load in a file called utils.js in the src
directory. It stores the module contents in a variable, and then use the
contents in the script.
If you run the above index.js script. you will see the message that is logged
from the tests function defined in the utils.js file.
Output:
Yehh! Local file is running successfully...
npm modules can be imported into your script using require. To load in an
npm module, pass the npm module name to require:
index.js: Write the below code in the index.js file
Javascript
// Print: true
// Print: false
Output:
39
Output:
Addition of 50 and 20 is 70
Subtraction of 50 and 20 is 30
Multiplication of 50 and 20 is 1000
Division of 50 and 20 is 2.5
What is Express?
Express is a small framework that sits on top of Node.js’s web server
functionality to simplify its APIs and add helpful new features.It makes it
easier to organize your application’s functionality with middle ware and
routing; it adds helpful utilities to Node.js’s HTTP objects;it facilitates the
rendering of dynamic HTTP objects.
Express.js is a fast, flexible and minimalist web framework for Node.js. It’s
effectively a tool that simplifies building web applications and APIs using
JavaScript on the server side. Express is an open-source that is developed
and maintained by the Node.js foundation.
Express.js offers a robust set of features that enhance your productivity and
streamline your web application. It makes it easier to organize your
application’s functionality with middleware and routing. It adds helpful utilities
to Node HTTP objects and facilitates the rendering of dynamic HTTP
objects.
4. **Static file serving**: Express makes it simple to serve static files, such
as images, CSS files, and JavaScript files, using the `express.static`
middleware. This middleware function serves files from a specified directory,
making it easy to include client-side assets in your web applications.
Benefits:
Fast and Minimalist: Express is known for its speed and minimalist approach. It
provides a lightweight framework that allows developers to build scalable and efficient
applications.
Large Ecosystem: Express has a vast ecosystem of modules and libraries, making it easy
to find solutions for common tasks and challenges in web development.
Flexibility: Express does not impose strict rules or conventions, allowing developers to
structure their applications according to their preferences and requirements.
Conclusion
Express.js is a powerful and flexible framework for building web applications and APIs
with Node.js.
Its simplicity, speed, and extensive feature set make it a popular choice among
developers for various projects.
Keep pressing enter and enter “yes/no” accordingly at the terminus line.
NOTE- Here “WARN” indicates the fields that must be entered in STEP-2.
STEP-4: Verify that Express.js was installed on your Windows:
To check that express.js was installed on your system or not, you can run
the following command line on cmd:
C:\Users\Admin\gfg\node_modules>npm --version express
44
})
Save the above code as index.js and run it from the command-line.
Application object
An object of the top level express class denotes the application
object. It is instantiated by the following statement −
app.listen(port, callback);
Basic Routing
48
The app object handles HTTP requests GET, POST, PUT and DELETE
with app.get(), app.post(), app.put() and app.delete() method
respectively. The HTTP request and HTTP response objects are
provided as arguments to these methods by the NodeJS server. The
first parameter to these methods is a string that represents the
endpoint of the URL. These methods are asynchronous, and invoke
a callback by passing the request and response objects.
GET method
You can print request and response objects which provide a lot of
information related to HTTP request and response including cookies,
sessions, URL, etc.
The response object also has a sendFile() method that sends the
contents of a given file as the response.
res.sendFile(path)
<html>
<body>
<h2 style="text-align: center;">Hello World</h2>
49
</body>
</html>
<html>
<body>
</body>
</html>
app.use(express.static('public'));
Visit http://localhost:5000/.
Now you can enter the First and Last Name and then click submit
button to see the result and it should return the following result −
{"first_name":"John","last_name":"Paul"}
POST method
The HTML form is normally used to submit the data to the server,
with its method parameter set to POST, especially when some
binary data such as images is to be submitted. So, let us change the
method parameter in index.html to POST, and action parameter to
"process_POST".
<html>
52
<body>
</body>
</html>
This is a node.js middleware for handling JSON, Raw, Text and URL
encoded form data.
};
console.log(response);
res.end(JSON.stringify(response));
})
app.use(express.static('public'));
Now you can enter the First and Last Name and then click the
submit button to see the following result −
{"first_name":"John","last_name":"Paul"}
You simply need to pass the name of the directory where you keep
your static assets, to the express.static middleware to start serving
the files directly. For example, if you keep your images, CSS, and
JavaScript files in a directory named public, you can do this −
app.use(express.static('public'));
node_modules
index.js
public/
public/images
public/images/logo.png
Save the above code in a file named index.js and run it with the
following command.
outside the web browser, enabling server-side scripting to build scalable network applications. Here's an
introduction to Node.js:
Key Features:
Use Cases:
1. Web Servers and APIs: Node.js is commonly used to build fast and scalable web
servers and APIs, powering a wide range of applications, including social networks, e-
commerce platforms, and content management systems.
2. Real-Time Applications: Its event-driven architecture makes Node.js well-suited for
building real-time applications like chat applications, online gaming platforms, and
collaboration tools, where instantaneous communication and updates are essential.
3. Microservices: Node.js is often used to build microservices architectures due to its
lightweight nature and ability to handle multiple microservices concurrently, facilitating
modularization and scalability in large-scale applications.
4. Data Streaming: Node.js is ideal for building data-intensive applications that involve
streaming large volumes of data, such as video streaming platforms, IoT (Internet of
Things) applications, and real-time analytics systems.
Conclusion:
rich ecosystem, and cross-platform compatibility make it a popular choice for building a wide
range of web and network applications.
What is Nodejs,
What is Node.JS?
Node.js is an open source server environment
Node.js is free
Node.js runs on various platforms (Windows, Linux, Unix, Mac OS X, etc.)
Node.js uses JavaScript on the server
Create a new directory for your Express.js project. You can do this using the command line:
bash
Copy code
mkdir my-express-app
cd my-express-app
Initialize a new Node.js project by running the following command in your project directory:
bash
Copy code
npm init -y
This command creates a package.json file in your project directory, which will hold
information about your project and its dependencies.
4. Install Express.js:
bash
Copy code
npm install express
This will download and install the Express.js framework in your project directory and add it to
your package.json file as a dependency.
Create a new JavaScript file (e.g., app.js) in your project directory and import the Express.js
module:
javascript
Copy code
const express = require('express');
const app = express();
const port = 3000;
res.send('Hello World!');
});
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
This code creates a simple Express.js application that listens for HTTP GET requests on the root
URL (/) and responds with "Hello World!".
Run your Express.js application by executing the following command in your project directory:
bash
Copy code
node app.js
This will start your Express.js server, and you should see a message indicating that the server is
running on http://localhost:3000.
Open your web browser and navigate to http://localhost:3000 to see your Express.js
application in action. You should see the "Hello World!" message displayed in the browser.
Congratulations! You've now created and run your first Express.js application. From here, you
can continue to explore and learn more about the features and capabilities of Express.js to build
more complex web applications and APIs.
Express is a web application framework for Node.js that allows you to spin up robust
APIs and web servers in a much easier and cleaner way. It is a lightweight package that
does not obscure the core Node.js features.
In this article, you will install and use Express to build a web server.
Prerequisites
If you would like to follow along with this article, you will need:
A local development environment for Node.js. Follow How to Install Node.js and Create
a Local Development Environment.
This tutorial was verified with Node v15.14.0, npm v7.10.0, express v4.17.1, and serve-
index v1.9.1.
Step 1 — Setting Up the Project
First, open your terminal window and create a new project directory:
60
1. mkdir express-example
2.
Copy
These lines of code is where we tell our Express server how to handle a GET request to
our server. Express includes similar functions for POST, PUT, etc.
using app.post(...), app.put(...), etc.
61
These functions take two main parameters. The first is the URL for this function to act
upon. In this case, we are targeting '/', which is the root of our website: in this
case, localhost:3000.
The second parameter is a function with two arguments: req, and res. req represents
the request that was sent to the server; We can use this object to read data about what
the client is requesting to do. res represents the response that we will send back to the
client.
Here, we are calling a function on res to send back a response: 'Successful
response.'.
server.js
const express = require('express');
Then, visit localhost:3000 in your web browser. Your browser window will
display: 'Successful response'. Your terminal window will display: 'Example app is
listening on port 3000.'.
And there we have it, a web server! However, we definitely want to send more than just
a single line of text back to the client. Let’s briefly cover what middleware is and how to
set this server up as a static file server!
We can write our own middleware functions or use third-party middleware by importing
them the same way we would with any other package.
Let’s start by writing our own middleware, then we’ll try using some existing middleware
to serve static files.
The next() call tells the middleware to go to the next middleware function if there is
one. This is important to include at the end of our function - otherwise, the request will
get stuck on this middleware.
We can optionally pass a path to the middleware, which will only handle requests to that
route. For example:
server.js
const express = require('express');
});
By passing '/request-type' as the first argument to app.use(), this function will only
run for requests sent to localhost:3000/request-type.
1. node server.js
2.
Copy
First, import the serve-index package at the top of the server file.
Then, include the express.static and serveIndex middlewares and tell them the path
to access from and the name of the directory:
server.js
const express = require('express');
const serveIndex = require('serve-index');
app.use('/public', express.static('public'));
app.use('/public', serveIndex('public'));
});
1. Create a project directory: Open your terminal and create a new directory for your
Express app. You can name it whatever you like:
bash
Copy code
mkdir my-express-app
cd my-express-app
2. Initialize a new Node.js project: Run the following command to create a package.json
file:
bash
Copy code
npm init -y
bash
Copy code
npm install express
4. Create your Express app: Now, create a new file named app.js (or any other name you
prefer) in your project directory, and add the following code:
javascript
Copy code
// Import the Express module
const express = require('express');
5. Run your Express app: Run the following command in your terminal to start the
Express server:
bash
Copy code
node app.js
6. Test your Express app: Open your web browser and navigate to
http://localhost:3000. You should see the text "Hello World!" displayed in the
browser window.
That's it! You've successfully created your first Express.js application. From here, you can
continue to explore and build more complex web applications and APIs using Express.js.
Step 2: Install the necessary dependencies for our application. In this, we will install
express.js dependency.
npm install express
Something like this will be shown on successful installation.
Step 4: Create an app.js (or server.js) file. This will serve as the main entry point for
your application.
Project Structure:
67
Now with all of this, we have created and run the server successfully, if your
server is not starting then there may be some error, try to analyze and read
68
//app.js
Step to run the application: Save this code, restart the server, and open the
localhost on the given port. When a client requests with the appropriate
method on the specified path ex: GET request on ‘/’ path, our function returns
the response as plain text If we open the network section in Chrome
developers tools (press Ctrl+Shift+I to open) we will see the response
returned by the localhost along with all information.
Output:
//app.js
Step to run the application: Save this code, restart the server, and open the
localhost on the given port. Now access the ‘/hello’ route from the browser,
The h1 text inside HTML will be shown as a response.
Output:
// app.js
app.use(express.json());
app.post('/', (req, res)=>{
const {name} = req.body;
res.send(`Welcome ${name}`);
})
Step to run the application: We are Accessing the route with Postman. It is a
tool to test APIs, we can use any other things like Axios, fetch, or any other
thing from the frontend or cURL from the terminal, but that will make you
divert from the topic, just keep in mind that our express server only demands
72
// app.js
Step to run the application: This will be the returned response when we
request some static file from the directory that we are serving as static. Here
you can see we have received an HTML file as a response
for ‘/static/random.html’. The same things happen when we request
for ‘/static/1.jpg’.
Output:
74
// app.js
Express Routing
Express express.Router() Function
The express.Router() function is used to create a new router object. This function is
used when you want to create a new router object in your program to handle requests.
Syntax:
express.Router( [options] )
Optional Parameters:
case-sensitive: This enables case sensitivity.
mergeParams: It preserves the req.params values from the parent router.
strict: This enables strict routing.
Return Value: This function returns the New Router Object.
Steps to Install the express module:
Step 1: You can install this package by using this command.
npm install express
Step 2: After installing the express module, you can check your express version in the
command prompt using the command.
npm version express
Step 3: After that, you can just create a folder and add a file, for example, index.js. To
run this file you need to run the following command.
node index.js
Project Structure:
Project Structure
// Single routing
const router = express.Router();
app.use(router);
Steps to run the program: Run the index.js file using the below command:
node index.js
Output:
Console Output:
Server listening on PORT 3000
Browser Output:
Now open your browser and go to http://localhost:3000/, you will see the following
output on your screen:
Server listening on PORT 3000
Router Working
Example 2: Below is the another code example of express.Router() Function
implementation.
javascript
const express = require('express');
const app = express();
const PORT = 3000;
// Multiple routing
const router1 = express.Router();
const router2 = express.Router();
app.use(router1);
app.use(router2);
app.use(router3);
app.listen(PORT, function (err) {
if (err) console.log(err);
console.log("Server listening on PORT", PORT);
});
Steps to run the program: Run the index.js file using the below command:
node index.js
Now make a GET request
to http://localhost:3000/user, http://localhost:3000/admin, and
http://localhost:3000/student, then you will see the following output on your console:
Output:
Server listening on PORT 3000
User Router Working
Admin Router Working
Student Router Working
Routing refers to how an application’s endpoints (URIs) respond to client requests. For an
introduction to routing, see Basic routing.
You define routing using methods of the Express app object that correspond to HTTP methods; for
example, app.get() to handle GET requests and app.post to handle POST requests. For a full
list, see app.METHOD. You can also use app.all() to handle all HTTP methods and app.use() to
specify middleware as the callback function (See Using middleware for details).
These routing methods specify a callback function (sometimes called “handler functions”) called
when the application receives a request to the specified route (endpoint) and HTTP method. In other
words, the application “listens” for requests that match the specified route(s) and method(s), and
when it detects a match, it calls the specified callback function.
78
In fact, the routing methods can have more than one callback function as arguments. With multiple
callback functions, it is important to provide next as an argument to the callback function and then
call next() within the body of the function to hand off control to the next callback.
// respond with "hello world" when a GET request is made to the homepage
app.get('/', (req, res) => {
res.send('hello world')
})
Route methods
A route method is derived from one of the HTTP methods, and is attached to an instance of
the express class.
The following code is an example of routes that are defined for the GET and the POST methods to
the root of the app.
// GET method route
app.get('/', (req, res) => {
res.send('GET request to the homepage')
})
Express supports methods that correspond to all HTTP request methods: get, post, and so on. For
a full list, see app.METHOD.
There is a special routing method, app.all(), used to load middleware functions at a path
for all HTTP request methods. For example, the following handler is executed for requests to the
route “/secret” whether using GET, POST, PUT, DELETE, or any other HTTP request method
supported in the http module.
app.all('/secret', (req, res, next) => {
console.log('Accessing the secret section ...')
79
Route paths
Route paths, in combination with a request method, define the endpoints at which requests can be
made. Route paths can be strings, string patterns, or regular expressions.
The characters ?, +, *, and () are subsets of their regular expression counterparts. The hyphen ( -)
and the dot (.) are interpreted literally by string-based paths.
If you need to use the dollar character ( $) in a path string, enclose it escaped within ([ and ]). For
example, the path string for requests at “/data/$book”, would be “/data/([\$])book”.
Express uses path-to-regexp for matching the route paths; see the path-to-regexp documentation for all the
possibilities in defining route paths. Express Route Tester is a handy tool for testing basic Express routes, although it
does not support pattern matching.
Query strings are not part of the route path.
})
This route path will match abcd, abbcd, abbbcd, and so on.
app.get('/ab+cd', (req, res) => {
res.send('ab+cd')
})
This route path will match abcd, abxcd, abRANDOMcd, ab123cd, and so on.
app.get('/ab*cd', (req, res) => {
res.send('ab*cd')
})
This route path will match butterfly and dragonfly, but not butterflyman, dragonflyman, and
so on.
app.get(/.*fly$/, (req, res) => {
res.send('/.*fly$/')
})
Express routing allows you to define routes to handle different HTTP requests and URLs in your
application. Routing is a fundamental aspect of building web applications and APIs with
Express.js. Here's how you can use routing in Express:
Basic Routing:
81
1. Defining Routes: In Express, you define routes using the HTTP methods ( GET, POST,
PUT, DELETE, etc.) and URL patterns. For example:
javascript
Copy code
// Respond to GET requests on the root URL
app.get('/', (req, res) => {
res.send('Hello from Express!');
});
2. Route Parameters: You can define route parameters in the URL pattern, which are
placeholders for dynamic values. For example:
javascript
Copy code
// Route with a parameter
app.get('/users/:userId', (req, res) => {
const userId = req.params.userId;
// Fetch user data based on userId
});
3. Route Handlers: Route handlers are callback functions that execute when a matching
route is accessed. They take two arguments: req (the request object) and res (the
response object). For example:
javascript
Copy code
app.get('/about', (req, res) => {
res.send('About Us');
});
Route Methods:
Express supports all standard HTTP methods ( GET, POST, PUT, DELETE, etc.) for defining routes.
Here's how you can use them:
javascript
Copy code
app.get('/products', (req, res) => {
// Handle GET request for retrieving products
});
Middleware in Routing:
You can use middleware functions in routing to perform tasks like authentication, logging, and
error handling. Middleware functions are executed in the order they are defined. For example:
javascript
Copy code
// Middleware function
function authenticate(req, res, next) {
// Check authentication
if (authenticated) {
next(); // Call the next middleware function
} else {
res.status(401).send('Unauthorized');
}
}
Route Chaining:
You can chain multiple route handlers together for a single route. This is useful for reusing
middleware across multiple routes. For example:
javascript
Copy code
app.get('/admin', authenticate, (req, res, next) => {
// Middleware for admin routes
// ...
next();
}, (req, res) => {
// Route handler for admin route
// ...
});
Express routing provides a flexible and powerful way to define the behavior of your web
application or API endpoints. By defining routes, handling requests, and using middleware
functions, you can create robust and scalable applications with Express.js.
MVC is simply a design or architectural pattern used in software engineering. Its main goal is to
split large applications into specific sections that each have their own purpose.
MVC also allows developers to logically structure applications in a secure way, which we will
demonstrate in this tutorial. But first, let’s break down what each layer of the pattern provides.
Model
As the name implies, a model is a design or structure that typically bounds with an OOP entity of
a specific software system.
In the case of MVC, the model determines how a database is structured, defining a section of the
application that interacts with the database. The model layer holds the database
connection/manipulation logic and exposes methods that only use model objects by putting an
abstraction layer over raw data formats used by the database. The ORM libraries help us define
models without worrying about database-to-model mapping.
View
The view is where end users interact within the application. Simply put, this is where all the
HTML template files go in MVC-architectured web apps. The view layer never communicates
directly with the model — it communicates with the model layer strictly through the controller.
Controller
The controller interacts with the model and serves the response and functionality to the view.
When an end user makes a request, it’s sent to the controller, which interacts with the database.
You can think of the controller as a waiter in a restaurant that handles customers’ orders, which
in this case is the view. The waiter then goes to the kitchen, which is the model/database and gets
food to serve the customers, which is the controller handling the request.
Now, let’s build a sample Node.js web app using the MVC pattern!
To understand how to use MVC, we will build a simple login and registration system with a
dashboard page that only authenticated users can access. However, this tutorial is more about
structure than about the application we are building.
Open up your terminal in an empty folder and run the following command to
create a new Node.js project:
npm init -y
# --- or ---
yarn init -y
84
For this project, we will need to install some packages to get started:
npm install express express-session pug sequelize sqlite3 bcryptjs passport
passport-local
# --- or ---
yarn add express express-session pug sequelize sqlite3 bcryptjs passport passport-
local
These packages provide the following facilities:
o express is used to implement the app’s HTTP endpoints and render
app views
o express-session is used to create an HTTP cookie-based user session
for Express routes
o pug is used to render server-side HTML views using Pug-based
templates
o sequelize implements ORM logic and helps define models with less
code
o sqlite3 works as the primary database system with
the sequelize package
o bycrptjs handles hashing passwords before saving them in the
database
o passport and passport-local handle authentication
After this is complete, you should see a node_modules folder (this is where
all the packages are downloaded to).
Let’s create our Express server instance that helps process and return HTTP
messages. Copy and paste the following code into the server.js file:
const express = require('express');
const app = express();
const PORT = 8080;
On line seven, we are now using the listen() method to start up a server
that runs at http://localhost:8080. To confirm that our server works
properly, run the following:
npm start
# --- or ---
yarn start
Open the server endpoint from the browser. You’ll see a greeting message as
follows confirming that the Express server works:
Now, our server is ready. Let’s add views, controllers, and routes!
The layout.pug code is included across all .pug files in the views folder.
First, add the following contents to the layout.pug file:
86
doctype html
head
meta(charset='utf-8')
title Node.js MVC Demo
meta(name='viewport' content='width=device-width, initial-scale=1')
link(href='https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css
' rel='stylesheet' integrity='sha384-
QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH'
crossorigin='anonymous')
nav.navbar.navbar-expand-lg.navbar-dark.bg-dark
.container-fluid
a.navbar-brand(href='#') Node.js MVC Demo
button.navbar-toggler(type='button' data-bs-toggle='collapse' data-bs-
target='#navbarSupportedContent' aria-controls='navbarSupportedContent' aria-
expanded='false' aria-label='Toggle navigation')
span.navbar-toggler-icon
if name
#navbarSupportedContent.collapse.navbar-collapse.justify-content-end
form.d-flex
span.navbar-text.text-light.pe-2 Hello #{name}
a.btn.btn-outline-light(href='/logout') Logout
.py-2
block content
script(src='https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.
min.js' integrity='sha384-
MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM'
crossorigin='anonymous')
We used the block content statement here to inject child template contents
from other .pug files.
server will create a complete HTML page that contains the login interface by
injecting login.pug into the layout.pug file with the help of the Pug
templating engine.
block content
.container
h4 Dashboard
span Only authenticated users can view this dashboard view.
We need to render these Pug templates from controllers by following MVC
project structuring practices, but let’s render them directly through
the server.js to test the views, as shown in the following code snippet:
const express = require('express');
const app = express();
const PORT = 8080;
Run the app. Now you can see the dashboard, login, and register views from
your web browser:
These views are not dynamic and form post actions won’t work yet, so we need to complete the
MVC app by creating controllers and models.
Creating controllers
A controller is responsible for generating a specific view by fetching data objects from models.
Controllers are usually mapped with routes/endpoints through handlers. For example,
the /login route will return the login.pug view by communicating with the login view
controller’s loginView handler.
Let’s create a new file to implement controller handlers related to login/register routes. Create a
file named auth.js inside the controllers folder and add the following code:
module.exports = {
registerView: (req, res) => {
res.render('register');
},
}
}
Here, registerView and loginView functions/handlers render
the register.pug and login.pug views, respectively. We’ll
use registerUser and loginUser functions for registering and authenticating
users after implementing models.
Create a controller for the dashboard page by adding the following contents
to the controllers/dashboard.js file:
module.exports = {
dashboardView: (req, res) => {
res.render('dashboard');
}
}
In large-scale apps, we can simplify the complex MVC app structure by linking controllers via
router modules. For example, the invoices router module can map all invoice-related controllers
with the /invoices router path.
Let’s use this practice in this MVC app too, so you can use this as a template for creating large-
scale apps. Create a new folder to store router modules:
mkdir routes
Create a new file named auth.js inside the routes folder and link log-in/register related controller
handlers with routes, as shown in the following code:
const express = require('express');
const authController = require('../controllers/auth');
const dashboardController = require('../controllers/dashboard');
module.exports = router;
Do the same for the dashboard controller by creating
the routes/dashboard.js router module:
const express = require('express');
const dashboardController = require('../controllers/dashboard');
module.exports = router;
Update the server.js file to use newly created router modules:
const express = require('express');
const authRoutes = require('./routes/auth');
90
If you use an ORM library, you undoubtedly don’t need to run database-specific queries and
handle connection management logic in normal use cases because ORMs internally do these as
inbuilt core features for you. We only have to define models and manipulate/query them with
methods provided by the ORM library.
Create a new file named db.js in the root of the project directory and add the following code to
set the database connection configuration for Sequelize.js:
Models are what communicate directly to our database. Let’s create a new
model for users in the models/User.js. file using the following code:
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = require('../db');
module.exports = sequelize.define(
91
'User',
{
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
},
name: {
type: DataTypes.STRING,
},
email: {
type: DataTypes.STRING,
unique: true,
},
password: {
type: DataTypes.STRING,
},
}
);
These are the fields we want to insert into the database whenever a new user registers through
the registration page. We can store a name, unique email address, hashed password, and auto-
generated incremental integer as the unique user identifier.
Update the server.js source file as follows to synchronize models with the SQLite and activate
HTTP-body-parser to fetch form data from post requests:
const express = require('express');
const authRoutes = require('./routes/auth');
const dashboardRoutes = require('./routes/dashboard');
const db = require('./db.js');
app.use(express.urlencoded({extended: false}));
app.set('view engine', 'pug');
app.use('/', authRoutes);
app.use('/', dashboardRoutes);
We have created a schema to store our user information in our database inside the User.js file
within the models folder. Now, we can insert a new user into the database from a controller using
the User model.
Whenever an end user hits the Register button in the register view, a POST request is sent to
the /register route (remember what we did before was a GET request). To make this work, we
must go to controllers/auth.js and require the User.js model and bcryptjs because we must hash
the password:
const bcrypt = require('bcryptjs');
const User = require('../models/User');
Next, update the registerUser handler in the controllers/auth.js with
the following implementation:
registerUser: async (req, res) => {
const { name, email, password } = req.body;
if(!name || !email || !password) {
return res.render('register', { error: 'Please fill all fields' });
}
res.redirect('login?registrationdone');
},
On line two, we get all the inputs submitted into the form by users:
const { name, email, password } = req.body;
req.body is an Express API object that holds the submitted form data through the frontend of our
application.
After line two, we validate incoming data fields with an if condition and send an error message
to register.pug if all fields are not properly filled.
Also, we check whether a user account already exists with the given email address by using
the User.findOne() Sequelize.js library method. If the specific email already exists on the
database, we send another error message to the register.pug template.
Note that here, we hash the password with bcryptjs before saving it in the database to improve
app security factors.
Run the app. Now when ever a user selects the Register button, if everything checks out, the
form will create a user instance in the database and redirect them to the login page, as shown in
the following preview:
93
module.exports = {
init: () => {
passport.use(
new LocalStrategy({ usernameField: 'email' }, async (email, password, done)
=> {
const user = await User.findOne({where: { email }});
if(!user) return done(null, false);
if(!bcrypt.compareSync(password, user.password)) return done(null, false);
return done(null, user);
})
);
},
protectRoute: (req, res, next) =>{
if(req.isAuthenticated()) {
94
return next();
}
res.redirect('/login?next=' + req.url);
}
};
The above code implements two exported functions:
o init(): This function is responsible for activating username and password-based
authentication strategy for Passport.js. This Passport.js configuration strategy uses email
as the username and the password field as the login password. The init() function returns
the User model if the user with the given email exists and the password comparison
process succeeds
o protectedRoute(): This handler works as an Express route protection middleware that
redirects unauthenticated users to the login page. We’ll use this handler to protect the
dashboard page of the sample MVC app
Now, we need to implement the loginUser handler of the controllers/auth.js file to complete the
authentication process. Update the loginUser handler as follows. Make sure to import passport:
loginUser: (req, res) => {
passport.authenticate('local', {
successRedirect: '/?loginsuccess',
failureRedirect: '/login?error'
})(req, res);
},
The above loginUser function authenticates users using Passport.js by
calling the passport.authenticate() function.
module.exports = router;
Finally, configure the Express session and initialize Passport.js from
your server.js file, as shown in the following source code:
const express = require('express');
const passport = require('passport');
const session = require('express-session');
const authRoutes = require('./routes/auth');
const dashboardRoutes = require('./routes/dashboard');
const db = require('./db.js');
const { init: initAuth } = require('./auth');
app.use(express.urlencoded({extended: false}));
app.set('view engine', 'pug');
95
initAuth();
app.use(session({
secret: 'secret',
saveUninitialized: true,
resave: true
}));
app.use(passport.initialize());
app.use(passport.session());
app.use('/', authRoutes);
app.use('/', dashboardRoutes);
You won’t see the logout button and greeting text yet in the navigation bar area when you are on
the dashboard page because we haven’t passed the name data field to the layout.pug template file
yet.
Pass the name data field to the layout.pug file to display the logout button and greeting line for
authenticated users. You can do so by updating the controllers/dashboard.js as
follows:
module.exports = {
dashboardView: (req, res) => {
res.render('dashboard', { name: req.user.name });
}
}
Here, we used only one data field called name to detect the login state from Pug templates, but in
production apps, you can pass a user details object to the template that contains their first name,
96
Also, when you visit the protected dashboard page without logging in, you will be redirected to
the login page. Don’t forget to test that, too.Now, the sample Node.js MVC is ready. You can
even use this structure for developing large-scale apps as we properly decomposed the project
into several folders and files.
1. Project Structure:
Create a project structure that separates your code into model, view, and controller directories:
go
Copy code
my-express-app/
├── controllers/
│ └── UserController.js
├── models/
│ └── User.js
├── views/
│ └── index.ejs
├── routes/
│ └── index.js
├── app.js
└── package.json
97
2. Model:
Define your data models in the models directory. These models represent the structure of your
application's data. For example, let's create a User model in models/User.js:
javascript
Copy code
// models/User.js
class User {
constructor(id, name, email) {
this.id = id;
this.name = name;
this.email = email;
}
}
module.exports = User;
3. View:
Create your views using template engines like EJS or Pug in the views directory. For example,
let's create an index.ejs file in views:
html
Copy code
<!-- views/index.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>User List</title>
</head>
<body>
<h1>User List</h1>
<ul>
<% users.forEach(user => { %>
<li><%= user.name %> (<%= user.email %>)</li>
<% }); %>
</ul>
</body>
</html>
4. Controller:
Define your route handlers in the controllers directory. These controllers handle the logic for
handling HTTP requests and rendering views. For example, let's create a UserController in
controllers/UserController.js:
javascript
Copy code
// controllers/UserController.js
98
const users = [
new User(1, 'John Doe', 'john@example.com'),
new User(2, 'Jane Doe', 'jane@example.com')
];
5. Routes:
Define your routes in the routes directory. These routes map HTTP requests to controller
actions. For example, let's create an index.js file in routes:
javascript
Copy code
// routes/index.js
const express = require('express');
const router = express.Router();
const UserController = require('../controllers/UserController');
router.get('/', UserController.getAllUsers);
module.exports = router;
6. App Setup:
In your app.js file, set up Express and configure routes, views, and middleware:
javascript
Copy code
// app.js
const express = require('express');
const app = express();
const indexRoutes = require('./routes/index');
// Routes
app.use('/', indexRoutes);
bash
Copy code
node app.js
Visit http://localhost:3000 in your browser to see the list of users rendered using the EJS
template.
Middleware in Express
Express serves as a routing and Middleware framework for handling the different routing of the
webpage and it works between the request and response cycle.
Middleware gets executed after the server receives the request and before the controller actions
send the response. Middleware has and access to the request object, responses object, and next,
it can process the request before the server sends a response. An Express-based application is a
series of middleware function calls. In this article, we will discuss what is middleware in
express.js.
Middleware working
Middleware functions take 3 arguments: the request object, the response object, and the next
function in the application’s request-response cycle, i.e., two objects and one function.
Middleware functions execute some code that can have side effects on the app and usually add
information to the request or response objects. They are also capable of ending the cycle by
sending a response when some condition is satisfied. If they don’t send the response when they
are done, they start the execution of the next function in the stack. This triggers calling the 3rd
argument, next().
The middle part (req,res,next)=>{} is the middleware function. Here we generally perform the
actions required before the user is allowed to view the webpage or call the data and many other
functions. So let us create our own middleware and see its uses.
Using Middleware in Express
Follow the steps below to use Middleware in Express.js:
Step 1: Go to your project directory and enter the following command to create a NodeJs
project. Make sure that NodeJs is installed in your machine.
npm init -y
Step 2: Install two dependencies using the following command.
npm install express nodemon
Step 3: In the scripts section of the package.json file, add the following code line.
"start": "nodemon index.js",
Step 4: Create an index.js file in the directory. Make sure that it is not inside any subdirectories
of the directory you are working in.
Project Structure:
Project Structure
Step to run the application: Run the code by entering the following command on the
terminal.
npm start
Output:
Example
Creating a Middleware in the app.get() function, modify accordingly to the following
code.
Javascript
app.get(
"/",
(req, res, next) => {
console.log("hello");
next();
},
(req, res) => {
res.send(
`<div>
<h2>Welcome to GeeksforGeeks</h2>
<h5>Tutorial on Middleware</h5>
</div>`
);
}
);
102
Output:
Middleware
Types of Middleware
Express JS offers different types of middleware and you should choose the middleware on the
basis of functionality required.
Application-level middleware: Bound to the entire application
using app.use() or app.METHOD() and executes for all routes.
Router-level middleware: Associated with specific routes
using router.use() or router.METHOD() and executes for routes defined within that router.
Error-handling middleware: Handles errors during the request-response cycle. Defined
with four parameters (err, req, res, next).
Built-in middleware: Provided by Express (e.g., express.static, express.json, etc.).
Third-party middleware: Developed by external packages (e.g., body-parser, morgan, etc.).
Middleware Chaining
Middleware can be chained from one to another, Hence creating a chain of functions that are
executed in order. The last function sends the response back to the browser. So, before sending
the response back to the browser the different middleware processes the request.
The next() function in the express is responsible for calling the next middleware function if there
is one.
Modified requests will be available to each middleware via the next function
In the above case, the incoming request is modified and various operations are
performed using several middlewares, and middleware is chained using the next
function. The router sends the response back to the browser.
Advantages of using Middleware
Middleware can process request objects multiple times before the server works for
that request.
Middleware can be used to add logging and authentication functionality.
Middleware improves client-side rendering performance.
Middleware is used for setting some specific HTTP headers.
Middleware helps with Optimization and better performance
Middleware in Express.js allows you to execute code during the request-response cycle. It can
modify request and response objects, terminate the request-response cycle, or call the next
middleware function in the stack. Middleware functions are essential for tasks like
authentication, logging, error handling, and data parsing. Here's how you can use middleware in
Express:
Built-in Middleware:
Express provides several built-in middleware functions that you can use in your application:
1. express.json(): This middleware parses incoming requests with JSON payloads and
populates the req.body property with the parsed JSON data.
2. express.urlencoded(): This middleware parses incoming requests with URL-encoded
payloads and populates the req.body property with the parsed data.
3. express.static(): This middleware serves static files (e.g., HTML, CSS, images) from
a specified directory.
Custom Middleware:
You can also create custom middleware functions to perform specific tasks. Middleware
functions take three arguments: req (the request object), res (the response object), and next (a
function to call the next middleware function in the stack).
javascript
Copy code
// Custom middleware function
const myMiddleware = (req, res, next) => {
// Perform tasks here
console.log('Middleware executed');
next(); // Call the next middleware function
};
You can apply middleware to specific routes or groups of routes using the app.use() or
router.use() methods.
javascript
Copy code
// Middleware function
const authenticate = (req, res, next) => {
// Check authentication
if (authenticated) {
next(); // Call the next middleware function
} else {
res.status(401).send('Unauthorized');
}
};
Express allows you to define error-handling middleware functions to catch and handle errors that
occur during the request-response cycle.
javascript
Copy code
// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something went wrong!');
});
Third-party Middleware:
You can also use third-party middleware packages in your Express application to add additional
functionality. Some popular middleware packages include morgan for logging HTTP requests
and helmet for securing HTTP headers.
javascript
Copy code
const morgan = require('morgan');
const helmet = require('helmet');
105
Middleware in Express.js provides a flexible and powerful mechanism for handling requests and
responses in your application. By using built-in, custom, and third-party middleware, you can
add functionality, improve security, and enhance the performance of your Express.js
applications.
First, you need to install the desired template engine using npm. For example, to install EJS, you
would run:
bash
Copy code
npm install ejs
Similarly, you can install other template engines like Pug (npm install pug), Handlebars (npm
install express-handlebars), or Mustache (npm install mustache-express).
In your Express application, you need to set up the template engine by configuring the view
engine and views directory:
javascript
Copy code
const express = require('express');
const app = express();
Replace 'ejs' with the name of the template engine you are using (e.g., 'pug', 'handlebars',
'mustache', etc.). Also, make sure to specify the directory where your template files are
located.
106
Create a template file in the specified views directory. For example, if you are using EJS, create
a file named index.ejs:
html
Copy code
<!-- views/index.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Express Template Engine Example</title>
</head>
<body>
<h1>Welcome to <%= title %></h1>
</body>
</html>
4. Rendering Templates:
In your route handler, render the template using res.render() and pass data as an object:
javascript
Copy code
app.get('/', (req, res) => {
res.render('index', { title: 'My Express App' });
});
You can pass dynamic data to your templates by interpolating variables or using control
structures provided by the template engine. For example, in EJS, you can use <%= %> to output
data and <% %> for control structures:
html
Copy code
<!-- views/user.ejs -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>User Profile</title>
</head>
<body>
<h1>User Profile</h1>
<p>Name: <%= user.name %></p>
<p>Email: <%= user.email %></p>
</body>
</html>
107
Conclusion:
Using template engines in Express.js allows you to generate dynamic HTML content easily by
combining data with HTML templates. By following these steps, you can configure and use
template engines like EJS, Pug, Handlebars, or Mustache in your Express.js application to create
dynamic and interactive web pages.
Error Handling
Error handling in Express.js involves capturing errors that occur during the request-response
cycle and responding to them appropriately. Express provides built-in error handling
mechanisms and middleware functions to handle errors efficiently. Here's how you can handle
errors in an Express.js application:
Express provides a default error-handling middleware function that catches errors thrown by
route handlers and middleware functions. You can define error-handling middleware using the
app.use() method with four parameters: err, req, res, and next.
javascript
Copy code
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Internal Server Error');
});
You can also define custom error-handling middleware functions to handle specific types of
errors. These middleware functions typically have three parameters: err, req, and res.
javascript
Copy code
app.use((err, req, res, next) => {
// Custom error handling logic
res.status(500).send('Internal Server Error');
});
In route handlers, you can handle errors by passing them to the next() function or using try-
catch blocks.
javascript
Copy code
app.get('/example', (req, res, next) => {
try {
108
When using async/await syntax, you can handle errors using try-catch blocks or by passing
errors to the next() function.
javascript
Copy code
app.get('/example', async (req, res, next) => {
try {
const result = await someAsyncFunction();
res.json(result);
} catch (err) {
next(err);
}
});
When handling errors, you can send appropriate error responses to the client using the
res.status() and res.send() methods.
javascript
Copy code
app.get('/example', (req, res, next) => {
try {
// Code that may throw an error
throw new Error('Something went wrong');
} catch (err) {
res.status(500).send('Internal Server Error');
}
});
Conclusion:
Error handling in Express.js is essential for handling unexpected errors that may occur during the
request-response cycle. By using built-in error handling middleware, custom error handling
middleware, and handling errors in route handlers, you can ensure that your Express.js
application responds gracefully to errors and maintains robustness and reliability.
Error handling in Express.js refers to the process of capturing and responding to errors that
occur during the execution of an Express application. In Express, you can handle errors using
middleware functions, which are functions that have access to the request and response objects,
as well as the next middleware function in the application’s request-response cycle.
109
Express has built-in error handling middleware, such as the app.use(function(err, req, res, next)
{}) function, which can be used to handle errors that are thrown or passed to the next()
function. You can also create your own error-handling middleware functions to handle specific
errors in your application.
It’s important to note that in Express, the order of middleware functions is important. Error-
handling middleware should be placed at the end of the middleware stack, after all, other
middleware functions, so that it can catch any errors that are not handled by the other
middleware.
In addition, it’s important to handle errors properly and provide a proper error message to the
user, rather than returning stack traces to the client in production.
Reason for using error handling used in express.js:
To prevent application crashes: Without error handling, unhandled errors can cause an
application to crash, leading to poor user experience and potential data loss. Error handling
allows you to capture and respond to errors, preventing them from causing a crash and
keeping the application running smoothly.
To provide meaningful error messages: Error handling allows you to provide meaningful
and user-friendly error messages to your users, rather than leaving them with a blank
screen or a default error message. This can help to improve the overall user experience and
prevent confusion or frustration.
To improve debugging: Error handling allows you to capture and log errors, making it
easier to debug your application and identify the root cause of any issues. This can save
time and effort when troubleshooting problems with your application.
To comply with standards and regulations: Proper error handling is often a requirement
for compliance with security standards and regulations. By handling errors correctly, you
can ensure that your application meets these standards and regulations.
Ways to Perform Error Handling:
1. Middleware function: Express.js has built-in support for error-handling middleware, which
allows you to handle errors that occur during the execution of the application.
Syntax:
app.use(function(error, request, response, next) {
// Handle the error
response.status(500).send('Internal Server Error');
});
2. Try-Catch statements: you can use try-catch statements to handle errors
that occur within specific blocks of code. This ensures that any errors that
occur are caught and handled in a controlled manner.
Syntax:
app.get('/', function (req, res) {
try {
// Code that might throw an error
110
} catch (error) {
// Handle the error
res.status(500).send('Internal Server Error');
}
});
3. Error logging: You can set up error logging so that any errors that occur
during the execution of the application are logged to a file or a database for
later analysis.
Syntax:
app.get('/', function (req, res) {
try {
throw new Error('Something went wrong');
} catch (error) {
console.error(error);
}
});
Error codes: You can set up error codes for different types of errors that occur during the
execution of the application. This makes it easier to identify and handle specific errors.
Error codes in Node.js are symbolic values that represent specific types of errors that can
occur during the execution of a program. Error codes are usually represented as strings and
are used to help identify and categorize different types of errors.
For example, the Node.js fs module uses error codes such as ‘ENOENT’ (no such file or
directory) or ‘EACCES’ (permission denied) to represent specific types of file system
errors.
When an error occurs in your Node.js application, you can access the error code by
checking the code property of the error object. For example, if you are using the fs.readFile
function, you can check the code property of the error object that is passed to the callback
to determine the type of error that has occurred.
Example:
const fs = require('fs');
}
});
4. HTTP status codes: You can use HTTP status codes to indicate the type of error that
occurred. For example, a status code of 400 (Bad Request) can indicate a validation error,
while a status code of 500 (Internal Server Error) can indicate a server-side error.
Syntax:
const http = require('http');
server.listen(8080);
By using any of the above, you can handle errors in a controlled and efficient manner, and
ensure that your application is robust and stable.
Let’s see some basic examples and explanations for Error Handling in Express.js:
Example 1: Using a middleware function: You can use a middleware function to handle
errors that occur during the execution of an application. The middleware function should have
four arguments: error, request, response, and next.
Javascript
const express = require('express');
const app = express();
app.listen(3000, () => {
console.log('App is listening on port 3000');
});
112
Steps to run the application: Write the below code in the terminal to run
the application:
node index.js
Output:
Explanation:
In this example, we define a custom error-handling middleware function errorhandler that
logs the error stack and sends a response with a status code of 500 and the message
“Something went wrong!”.
We then use the custom error handling middleware by adding the app.use(errorhandler)
after defining it.
This error-handling middleware will catch any errors thrown in the previous middleware or
routes, and handle them according to the logic defined in the errorHandler function.
The first line App is listening on port 3000 is logged when the Express app starts listening
on port 3000.
If you make a request to the app, the custom middleware will throw an error, which will
then be caught by the error-handling middleware. The error stack trace will be logged to
the console, and the response sent to the client will have a status code of 500 and the
message “Something went wrong!”.
Example 2: Using the try-catch statement: You can use the try-catch statement to handle
errors that occur within a specific block of code.
Javascript
const express = require('express');
const app = express();
113
app.listen(3000, () => {
console.log('App is listening on port 3000');
});
Explanation:
In this example, we wrap the code that might throw an error in a try block.
If an error is thrown, it will be caught by the corresponding catch block,
which logs the error stack and sends a response with a status code of
500 and the message “Something went wrong!”.
This approach allows for more fine-grained error handling, as the try-
catch statement can be used multiple times in different middleware
functions or routes.
Steps to run the application: Write the below code in the terminal to run
the application:
node index.js
Output:
114
Explanation:
If you make a request to the app, the custom middleware will throw an error, which will
then be caught by the try-catch statement. The error stack trace will be logged to the
console, and the response sent to the client will have a status code of 500 and the message
“Something went wrong!”.
Note that the [ERROR STACK TRACE] part of the output will vary depending on the
exact error that was thrown. It will contain details about the error, such as the error
message and the location in the code where the error was thrown.
his output will be displayed if you make a request to the app and an error is thrown by the
custom middleware. The error stack trace will be logged to the console and the response
sent to the client will have a status code of 500 and the message “Something went wrong!”.
This output will be displayed when the Express app starts listening on port 3000. No error
will be thrown if you do not make any requests to the app.
Example 3: Using the next() function: You can use the next() function to pass errors to
the next middleware function in the chain.
Javascript
const express = require('express');
const app = express();
app.listen(3000, () => {
console.log('App is listening on port 3000');
});
Explanation:
In this example, we have two middleware functions. The first middleware function throws
an error, and the second middleware function is used for error handling. If an error is
thrown in the first middleware function, the control flow is passed to the second
middleware function using the next() function. The error is then logged to the console and a
response with a status code of 500 and the message “Something went wrong!” is sent to the
client.
115
This approach allows for error handling to be handled separately from the middleware
functions that perform the core functionality of the application.
Steps to run the application: Write the below code in the terminal to run the application:
node index.js
Here’s an example using curl:
Open a terminal or command prompt.
Navigate to the directory where the program is located.
Start the application by running node app.js.
In another terminal window, run the following command to make a request to the ‘/’
endpoint:
curl http://localhost:3000
Output:
If you make a request to the app, the first middleware function will throw an error. The
error will be passed to the second middleware function using the next() function, where it
will be logged to the console and a response with a status code of 500 and the message
“Something went wrong!” will be sent to the client.
Note that the [ERROR STACK TRACE] part of the output will vary depending on the
exact error that was thrown. It will contain details about the error, such as the error
message and the location in the code where the error was thrown.
Advantages of error handling used in express.js:
1. Improved user experience: Error handling allows you to provide meaningful and user-
friendly error messages to your users, rather than leaving them with a blank screen or a
default error message. This improves the overall user experience and can help to prevent
confusion or frustration.
2. Better debugging: When errors occur in an application, it can be difficult to identify the
cause without proper error handling. By capturing and logging errors, you can more easily
debug your application and identify the root cause of any issues.
116
3. Increased application stability: Error handling helps to prevent unhandled errors from
crashing your application, which can lead to increased stability and fewer downtime
incidents.
4. Better maintainability: Error handling makes it easier to maintain your application by
providing a clear and consistent way to handle errors. This can make it easier to identify
and fix bugs, as well as to add new features.
Disadvantages of error handling used in express.js:
1. Increased complexity: Error handling can add complexity to your application, as it
requires you to anticipate and plan for potential errors. This can make your code more
difficult to understand and maintain.
2. Overhead: Error handling can add overhead to your application, as it requires additional
logic and processing to capture and respond to errors. This can impact the performance of
your application.
3. False alarms: If error handling is not implemented correctly, it can lead to false alarms or
unnecessary error messages being displayed to users. This can create confusion and
damage user trust.
4. Security risks: Improper error handling can create security risks, as it can reveal sensitive
information or provide attackers with clues about potential vulnerabilities in your
application.
2. Define Routes: Define routes for your API endpoints. These routes will handle incoming
requests and execute the appropriate logic.
3. Handle Requests: Implement the logic to handle incoming requests inside route
handlers. This may involve interacting with external APIs, processing data, and sending
responses.
5. Error Handling: Implement error handling middleware to catch and handle errors that
occur during request processing.
6. Testing: Test your API endpoints using tools like Postman or by writing automated tests using
libraries like Jest or Mocha.
7. Documentation: Document your API endpoints, request/response formats, and any
authentication requirements for developers who will be consuming your API.
By following these steps, you can effectively handle APIs in Express and build robust web applications
that interact with external services.
Debugging
In express, there is a module present called DEBUG that gives log information. It tells about
middleware functions, application mode, their status, and also about the requests and responses
made to the server.
To use this module while running the express app, set the DEBUG environment variable to
express:*
$ DEBUG=express:* node index.js
119
These logs help in finding any bug in the program and tell which part of the program is
creating the problem.
Sometimes you may not want the entire log but only the logs from a specific part of the
program, for example, only the logs of the router or application, then you can do so by setting
the DEBUG environment variable as express:* and then running the command:
$ DEBUG=express:router node index.js
This gives logs only of the router part. Similarly, you can do for application as well.
$ DEBUG=express:application node index.js
If you want for both of them you can do so by running the code:
DEBUG = express:application,express:router node index.js
In the example above, whose image is shown we have set DEBUG to express:* . Here, *
indicates that all the areas are included and all the logs will be shown.
For windows
The above-shown method is for Linux. For Windows, you need to edit the package.json file. In
the package.json file set your start command as shown and run npm start.
"scripts": {
"start": "set DEBUG=express:* & node index.js"
}
You can also use more than one option at a time to debug them together by separating them by
commas. Example:
$ DEBUG=mail,express:* node index.js
Debug environment variables
120
Suppose you want the logs to be visible in a different manner. Suppose you don’t want the
colors to appear or you want to see some hidden information, you can do that by setting
environment variables. Some of these variables are:
1. DEBUG: Select the namespaces for which you want to see the logs.
2. DEBUG_COLORS: By setting this to either 1 or 0 you can decide whether the logs that
will be visible will be in different colors or the same white color. If you set
DEBUG_COLORS to 0 the logs will appear in white plain text. By default, it is set to 0.
3. DEBUG_HIDE_DATE: This can hide the date from debug output.
4. DEBUG_SHOW_HIDDEN: This shows hidden properties on inspected objects.
Example: You don’t want the log output to be displayed in different colors, set
DEBUG_COLORS =1
$ DEBUG=express:* DEBUG_COLORS=0 node gfg1.js
Its output is shown below:
Debugging in Express involves identifying and resolving issues in your application code,
middleware, routes, and configurations. Here are some debugging techniques you can use in
Express:
1. Console Logging: One of the simplest and most effective ways to debug Express
applications is by using console.log() statements. You can place these statements
throughout your code to print variables, object properties, and messages to the console,
helping you understand the flow of execution and the values of variables at different
points.
javascript
Copy code
app.get('/route', (req, res) => {
console.log('Received GET request');
// Other logic
});
javascript
Copy code
const expressDebug = require('express-debug');
121
javascript
Copy code
app.use((err, req, res, next) => {
console.error('Error:', err);
res.status(500).send('Internal Server Error');
});
4. Logging Middleware: Use logging middleware like morgan to log HTTP requests and
responses. This can help you track the flow of requests through your application and
identify any issues with request handling or response generation.
javascript
Copy code
const morgan = require('morgan');
5. Debugger: You can use Node.js's built-in debugger or a debugger like VS Code's
debugger to set breakpoints in your code and inspect variables, call stack, and execution
flow during runtime.
6. Error Stack Trace: When an error occurs, pay attention to the error stack trace printed
in the console. It provides valuable information about the location and cause of the error,
helping you identify the source of the problem.
7. Environment Variables: Use environment variables to control the behavior of your
application in different environments (e.g., development, staging, production). This
allows you to isolate and debug issues specific to a particular environment.
javascript
Copy code
if (process.env.NODE_ENV === 'development') {
// Enable additional debugging features
}
8. Testing: Write unit tests and integration tests for your Express application using testing
frameworks like Mocha, Chai, or Jest. Automated tests help identify and fix issues early
in the development process.
By using these debugging techniques, you can effectively identify and resolve issues in your
Express application, ensuring that it runs smoothly and handles requests correctly.
122
The following code is an example of implementing a very simple template engine for rendering .ntl files.
Your app will now be able to render .ntl files. Create a file named index.ntl in the views directory with the
following content.
#title#
#message#
Developing a template engine specifically for Express involves integrating your template engine
with Express's view rendering system. Express supports multiple template engines out of the
box, such as Pug (formerly Jade), EJS, Handlebars, and more. However, if you want to develop
your own template engine for Express, you can follow these general steps:
123
1. Understand Express View Rendering: Understand how Express renders views. Express
uses the res.render() function to render views. It looks for templates in a specified
directory and uses a template engine to render them.
2. Choose a Syntax: Decide on the syntax for your template engine. It should be easy to
read and write for developers. Consider common features like variables, conditionals,
loops, and partials.
3. Implement Template Engine: Implement your template engine logic. This involves
parsing the template files and rendering them into HTML. You'll need to create a
function that takes the template file path, data, and callback, and returns the rendered
HTML.
4. Integrate with Express: Integrate your template engine with Express. You'll need to
register your engine with Express using the app.engine() method, specify the file
extension associated with your engine, and set the directory where your templates are
located using app.set('views', 'views-directory').
5. Render Views: Use res.render() in your route handlers to render views using your
template engine. Pass data to your views as needed.
Here's a basic example of how you might implement a custom template engine for Express:
javascript
Copy code
// Custom template engine for Express
const fs = require('fs');
// Example route
app.get('/', (req, res) => {
res.render('index', { name: 'John' }); // Renders index.custom
});
In this example, the customEngine function reads the template file, replaces placeholders with
data from the options object, and invokes the callback with the rendered HTML. The engine is
registered with Express using app.engine() and associated with the .custom file extension.
Keep in mind that this is a simplified example. Depending on your requirements, you may need
to implement additional features such as layout support, partials, caching, and error handling.
124
Node.js process manager is a tool, which provides an ability to control application lifecycle, monitor
the running services and facilitate common system admin tasks to maintain your project operability.
The platform provides three pre-configured process managers by default, which can be selected in
the following ways:
by selecting the appropriate tag during the environment creation or container redeploy
by editing the PROCESS_MANAGER Docker environment variable in the already created container(s)
with the forever, npm, or pm2 value (restart is needed to apply the new options)
Below, we’ll consider each of the available managers to help you select one:
Process Manager (npm)
PM2
Forever
the PROCESS_MANAGER variable on the NodeJS container. As a result, the script defined in “start”
of package.json is launched.
Refer to the official documentation for additional information.
PM2
PM2 provides a huge variety of application management features, including the launched NodeJS
processes monitoring. You can get acquainted with the list of commands for pm2, which can be
executed directly via SSH.
For example, after Node.js server creation, you can list the running processes with the following
command:
1 pm2 list
Also, PM2 provides users the ability to create the configuration files where all the run options are
listed, which is useful for microservice-based applications deployment, as several apps can be
described in a single file. The appropriate config file reference can be found by following the
provided link (e.g. the default ecosystem.config.js file is used to launch the server.js application file
as the “draw game” application).
Forever
The forever process manager is the simple CLI tool, which allows to make your NodeJS processes run
continuously. It permanently keeps a child process (such as your project on the Node.js web server)
and automatically restart it upon failure.
Run the next command to get the main information on the forever manager usage, actions, usage,
etc.:
1 forever --help
126
Also, using forever you can specify the application options in a JSON file. For example, for the default
Draw game (available after Node.js server installation), this /home/jelastic/ROOT/forever.json file
looks like:
1 {
2 "uid": "app1",
3 "append": true,
4 "watch": true,
5 "script": "server.js",
6 "sourceDir": "/home/jelastic/ROOT"
7 }
where:
uid - sets unique name for your app
append - selects if logs should be supplemented (true) or overwritten (false)
watch - allows enabling or disabling automatic restart of a child process upon the appropriate
application code changes; set to “false”, if you want to avoid unexpected restart after deployment
from VCS (including auto-deploy)
script - defines a name of the executable .js file
sourceDir - provides an absolute path to the specified script
Security Measures:
1. Input Validation: Always validate user input to prevent injection attacks like SQL
injection, XSS (Cross-Site Scripting), and other forms of attacks. You can use libraries
like express-validator for this purpose.
2. Authentication: Implement user authentication using robust techniques like JWT (JSON
Web Tokens), OAuth, or Passport.js. Ensure passwords are hashed securely using bcrypt
or similar libraries.
127
Deployment: