Node.js and Express.js basics tutorial
To get started with Node.js, it is recommended that you are familiar with JavaScript programming. If you haven't learned how to write code in JavaScript, it is recommended to learn that first. However, if you are already familiar with JavaScript, you can get started with Node.js right away.
JavaScript Tutorial: JavaScript
Concepts:
14. Installing and Managing Packages
16. Event loop and Asynchronous Programming
20. Handling HTTP requests (GET, POST, PUT, DELETE)
26. Connetion to MySQL Database
27. Connetion to MongoDB Database
28. CRUD Operations using MySQL Database
29. CRUD Operations using MongoDB Database
1. What is Node.js?
Node.js, developed by Ryan Dahl in 2009, is a widely used open-source runtime environment that enables developers to create server-side applications using JavaScript.
It is built on top of the V8 JavaScript engine, the same engine that powers Google Chrome, making it exceptionally speedy and efficient.
Node.js stands out with its event-driven, non-blocking I/O model, which allows it to manage multiple requests simultaneously without blocking any threads. This results in superior performance and faster response times, making it an excellent choice for building high-performance applications that require handling a large number of concurrent connections.
2. Installing Node.js
Step 1: Download the Installer
To begin, visit the official Node.js website and download the appropriate installer for your operating system. Be sure to select the correct version that matches your system. You can find the download link at https://nodejs.org.
Step 2: Run the Installer
Once the installer has finished downloading, run it and follow the instructions provided to install Node.js on your computer. If you're using Windows, simply double-click the downloaded file and follow the prompts in the installation wizard. If you're on macOS, drag the downloaded file to your Applications folder and double-click it to open it.
Step 3: Verify the Installation
After the installation process is complete, open a command prompt or terminal window and type "node -v" to confirm that Node.js has been installed correctly. If everything has gone smoothly, you should see the version number of Node.js displayed.
That's it! With Node.js installed on your system, you're now ready to start building applications using this powerful framework.
3. Hello World!
In the text editor, create a new file and save it with a ".js" extension (e.g., "server.js").
In the file, write the following code
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World!');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
This code uses the http module to create a server that listens for requests on port 3000. When a request is received, the server responds with a status code of 200 and the message "Hello World!".
Save the file and Open your command prompt or terminal, navigate to the directory where the "server.js" file is saved, and type the following command
node server.js
This will start the server and print the message "Server running at http://127.0.0.1:3000/" to the console.
Open your web browser and go to http://127.0.0.1:3000/. You should see the message "Hello World!" displayed on the page.
Congratulations, you've just written "Hello World!" in Node.js with a server!
4. Node.js Core Modules
Modules are collections of code that provide specific functionality to your Node.js applications.
Node.js Core Modules are built-in modules that come bundled with Node.js and provide fundamental functionality such as file system access, networking, and cryptography. Some examples of core modules are fs, http, https, crypto, path, os, and util.
To use these core modules, simply require them in your Node.js code, like so
const fs = require('fs');
const http = require('http');
const https = require('https');
const path = require('path');
const crypto = require('crypto');
const os = require('os');
const util = require('util');
Third-party Modules are modules that are created and maintained by the Node.js community and can be installed using the Node Package Manager (NPM). These modules provide additional functionality such as date parsing, database connectivity, and user authentication. Some popular third-party modules include Express, Mongoose, Socket.IO, Passport, and Moment.js.
5. Global Objects
Global objects in Node.js are objects that are available in all modules without the need for importing or requiring them. These objects provide built-in functionality that can be used to simplify your code and improve the efficiency of your applications.
Here are some commonly used global objects in Node.js
1. console: The console object provides a simple debugging tool for Node.js applications. It has several methods for outputting messages to the console, including log(), warn(), and error().
console.log("Hello, world!"); // Output: Hello, world!
2. process: The process object provides information about the Node.js process running your application, such as the command-line arguments used to start the process and the environment variables set for the process.
console.log(process.argv); // an array of command-line arguments passed to the Node.js process
3. setTimeout and setInterval: These global functions provide a way to execute a function after a certain amount of time has elapsed (for setTimeout) or at regular intervals (for setInterval).
setTimeout(() => {
console.log("Delayed Hello, world!"); // Output: Delayed Hello, world! (after 1 second)
}, 1000);
let counter = 1;
const intervalId = setInterval(() => {
console.log(`Interval ${counter++}`); // Output: Interval 1, Interval 2, Interval 3, ...
if (counter > 5) {
clearInterval(intervalId);
}
}, 1000);
4. __dirname and __filename: These global variables provide the absolute path of the directory and file containing the currently executing module, respectively.
console.log(__dirname); // the absolute path of the directory containing the currently executing module
console.log(__filename); // the absolute path of the file containing the currently executing module
6. File system module
The file system module in Node.js is used to interact with the file system of your operating system. It provides functionality for reading, writing, updating, and deleting files and directories. To use this module, you need to require it at the beginning of your code like this
const fs = require('fs');
Once you have required the fs module, you can use its methods to perform various file system operations.
1. Reading a file
The "fs.readFile()" method is used to read the contents of a file. It takes two arguments: the path of the file to be read, and a callback function that will be called with the contents of the file as its argument.
fs.readFile('file.txt', (err, data) => {
if (err) throw err;
console.log(data.toString()); // the contents of file.txt
});
2. Writing to a file
The "fs.writeFile()" method is used to write data to a file. It takes three arguments: the path of the file to be written, the data to be written, and a callback function that will be called when the write operation is complete.
fs.writeFile('file.txt', 'Hello, World!', (err) => {
if (err) throw err;
console.log('Data written to file'); // Output: Data written to file
});
3. Updating a file
The "fs.appendFile()" method is used to append data to the end of a file. It takes two arguments: the path of the file to be updated, and the data to be appended.
fs.appendFile('file.txt', 'More data', (err) => {
if (err) throw err;
console.log('Data appended to file'); // Output: Data appended to file
});
4. Deleting a file
The fs.unlink() method is used to delete a file. It takes one argument: the path of the file to be deleted.
const fs = require('fs');
// Create a file named "example.txt"
fs.writeFile('example.txt', 'This is an example file', (err) => {
if (err) throw err;
console.log('File created');
// Delete the file
fs.unlink('example.txt', (err) => {
if (err) throw err;
console.log('File deleted');
});
});
7. Path module
The path module in Node.js provides functionality for working with file and directory paths. It is included as a core module in Node.js, which means you can use it without installing any additional dependencies.
To use the path module in your Node.js application, you can require it at the beginning of your code like we did for 'fs' module
const path = require('path');
Once you have required the path module, you can use its methods to manipulate file and directory paths. Here are some of the most commonly used methods of the 'path' module
1. path.join(): this method is used to join one or more path segments together. It takes any number of arguments and returns a normalized path.
const pathSegments = ['dir1', 'dir2', 'file.txt'];
const filePath = path.join(...pathSegments);
console.log(filePath); // Output: dir1/dir2/file.txt
2. path.resolve(): This method is used to resolve a sequence of paths or path segments into an absolute path. It takes any number of arguments and returns an absolute path.
const absolutePath = path.resolve('dir1', 'dir2', 'file.txt');
console.log(absolutePath); // Output: /Users/username/dir1/dir2/file.txt
3. path.dirname(): This method is used to get the directory name of a path. It takes a path as its argument and returns the directory name.
const dirName = path.dirname('/Users/username/dir1/dir2/file.txt');
console.log(dirName); // Output: /Users/username/dir1/dir2
4. path.basename(): This method is used to get the basename of a path. It takes a path as its argument and returns the last portion of the path.
const baseName = path.basename('/Users/username/dir1/dir2/file.txt');
console.log(baseName); // Output: file.txt
5. path.extname(): This method is used to get the extension of a file. It takes a path as its argument and returns the extension (including the dot).
const extName = path.extname('/Users/username/dir1/dir2/file.txt');
console.log(extName); // Output: .txt
6. path.parse(): This method is used to parse a path into its components (root, dir, base, ext, and name). It takes a path as its argument and returns an object containing the components.
const pathObj = path.parse('/Users/username/dir1/dir2/file.txt');
console.log(pathObj);
// Output:
// {
// root: '/',
// dir: '/Users/username/dir1/dir2',
// base: 'file.txt',
// ext: '.txt',
// name: 'file'
// }
8. OS module
The os module in Node.js provides a way to interact with the operating system on which Node.js is running. It is included as a core module in Node.js
To use the os module in your Node.js application, you can require it at the beginning of your code
const os = require('os');
Once you have required the os module, you can use its methods to get information about the operating system, such as the amount of free memory, the number of CPUs, the hostname, and more.
1. os.cpus(): This method returns an array of objects containing information about each CPU/core of the system.
const cpus = os.cpus();
console.log(cpus);
/* output:
[
{
model: 'Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz',
speed: 2592,
times: { user: 2600635, nice: 0, sys: 1639343, idle: 48441171, irq: 0 }
},
{
model: 'Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz',
speed: 2592,
times: { user: 170752, nice: 0, sys: 702847, idle: 53784550, irq: 0 }
},
{
model: 'Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz',
speed: 2592,
times: { user: 298285, nice: 0, sys: 172573, idle: 53655062, irq: 0 }
},
{
model: 'Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz',
speed: 2592,
times: { user: 243956, nice: 0, sys: 148228, idle: 53987286, irq: 0 }
}
]
*/
2. os.freemem(): This method returns the amount of free system memory in bytes.
const freeMem = os.freemem();
console.log(freeMem); // Output: 1488206848
3. os.hostname(): This method will the hostname of the OS.
const hostName = os.hostname();
console.log(hostName); // Output: MacBook-Pro.local
4. os.platform(): This method returns the operating system platform.
const platform = os.platform();
console.log(platform); // Output: darwin
5. os.totalmem(): This method returns the total amount of system memory in bytes.
const totalMem = os.totalmem();
console.log(totalMem); // Output: 16777216000
6. os.type(): This method returns the operating system name.
const osType = os.type();
console.log(osType); // Output: Darwin
These are just a few examples of the os module's capabilities. The os module provides many more methods for interacting with the operating system, such as getting the load averages, the network interfaces, the system uptime, and more.
9. URL module
The url module in Node.js provides a way to parse, manipulate, and resolve URLs. It is also included as a core module in Node.js
You know that, to use the url module in your Node.js application, you can require it at the beginning of your code
const url = require('url');
Once you have required the url module, you can use its methods to parse URLs into their component parts, create URLs from their component parts, and resolve URLs against a base URL
1. url.parse(): This method parses a URL string and returns an object containing its component parts.
const parsedUrl = url.parse('https://www.example.com/path?foo=bar#fragment');
console.log(parsedUrl);
/*
Output:
Url {
protocol: 'https:',
slashes: true,
auth: null,
host: 'www.example.com',
port: null,
hostname: 'www.example.com',
hash: '#fragment',
search: '?foo=bar',
query: 'foo=bar',
pathname: '/path',
path: '/path?foo=bar',
href: 'https://www.example.com/path?foo=bar#fragment'
}
*/
2. url.format(): This method takes an object containing URL components and returns a formatted URL string.
const formattedUrl = url.format({
protocol: 'https:',
hostname: 'www.example.com',
pathname: '/path',
search: '?foo=bar'
});
console.log(formattedUrl); // Output: https://www.example.com/path?foo=bar
3. url.resolve(): This method resolves a URL against a base URL and returns the result.
const resolvedUrl = url.resolve('https://www.example.com', '/path');
console.log(resolvedUrl); // Output: https://www.example.com/path
10. HTTP module
The HTTP module in Node.js allows you to make HTTP requests and create HTTP servers. It provides a simple interface for sending and receiving data over HTTP, making it a powerful tool for building web applications and APIs.
1. http.createServer()This method creates an HTTP server that listens for incoming requests on a specified port.
const http = require('http');
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello, world!');
});
server.listen(3000, () => {
console.log('Server running on http://localhost:3000/');
});
Here we're creating an HTTP server that listens on the port 3000. When a request is received, we set the status code to 200, set the Content-Type header to text/plain, and send the response body "Hello, world!" using the res.end() method.
2. http.request() This method sends an HTTP request to a specified URL and returns a http.ClientRequest object
const http = require('http');
const options = {
hostname: 'www.google.com',
port: 80,
path: '/',
method: 'GET'
};
const req = http.request(options, (res) => {
console.log(`statusCode: ${res.statusCode}`);
res.on('data', (data) => {
console.log(data.toString());
});
});
req.on('error', (error) => {
console.error(error);
});
req.end();
In this example, we're sending an HTTP GET request to www.google.com. We define the request options, including the hostname, port, path, and method, and create an http.ClientRequest object using the http.request() method. We then handle the response using a callback function that logs the response status code and any data received from the server.
3. http.get()This method sends an HTTP GET request to a specified URL and returns a http.ClientRequest object.
const http = require('http');
http.get('http://www.google.com/', (res) => {
console.log(`statusCode: ${res.statusCode}`);
res.on('data', (data) => {
console.log(data.toString());
});
}).on('error', (error) => {
console.error(error);
});
In this example, we're sending an HTTP GET request to www.google.com using the http.get() method. We handle the response using a callback function that logs the response status code and any data received from the server.
Sending JSON Data
To send JSON data in an HTTP request, you can use the JSON.stringify() method to convert an object to a JSON string, and then set the Content-Type header to application/json.
const http = require('http');
const data = JSON.stringify({
name: 'John Doe',
email: 'johndoe@example.com'
});
const options = {
hostname: 'httpbin.org',
port: 80,
path: '/post',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
};
const req = http.request(options, (res) => {
console.log(`statusCode: ${res.statusCode}`);
res.on('data', (data) => {
console.log(data.toString());
});
});
req.on('error', (error) => {
console.error(error);
});
req.write(data);
req.end();
In this example, we're sending a JSON object to the httpbin.org API using a POST request. We define the data as a JSON string using JSON.stringify(), and set the Content-Type header to application/json to indicate that we're sending JSON data.
Sending Form Data
To send form data in an HTTP request, you can use the querystring module to convert an object to a URL-encoded string, and then set the Content-Type header to application/x-www-form-urlencoded.
const http = require('http');
const querystring = require('querystring');
const data = querystring.stringify({
name: 'John Doe',
email: 'johndoe@example.com'
});
const options = {
hostname: 'httpbin.org',
port: 80,
path: '/post',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': data.length
}
};
const req = http.request(options, (res) => {
console.log(`statusCode: ${res.statusCode}`);
res.on('data', (data) => {
console.log(data.toString());
});
});
req.on('error', (error) => {
console.error(error);
});
req.write(data);
req.end();
Redirecting HTTP Requests
To redirect an HTTP request to another URL, you can set the Location header to the new URL and the 302 status code.
const http = require('http');
const server = http.createServer((req, res) => {
res.statusCode = 302;
res.setHeader('Location', 'https://www.google.com/');
res.end();
});
server.listen(3000, () => {
console.log('Server running on http://localhost:3000/');
});
In this example, we're creating an HTTP server that redirects all requests to Google's home page. We set the Location header to https://www.google.com/ and the status code to 302 to indicate that the request has been temporarily moved.
11. Events
In Node.js, events are a core part of the programming model. They allow developers to write code that can respond to specific actions or behaviors that occur in the application, such as a user clicking a button or a file finishing loading.
Events in Node.js are based on the Observer design pattern, where an object maintains a list of its dependents (observers) and notifies them automatically of any state changes. In Node.js, the object that emits the events is called an EventEmitter.
EventEmitter class
The EventEmitter class is a core module in Node.js that provides the ability to emit named events and attach listeners to those events. To use the EventEmitter class, we need to first create an instance of it, which can be done using the following code
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
This creates an instance of the EventEmitter class and assigns it to the myEmitter variable. We can now use the methods of the myEmitter object to emit events and attach listeners to those events.
Emitting Events
To emit an event, we can use the emit() method of the EventEmitter class. The emit() method takes two arguments: the name of the event, and an optional data object that will be passed to the event handler function.
myEmitter.emit('hello');
This code emits an event named 'hello' using the myEmitter object.
Listening for Events
To listen for an event, we can use the on() method of the EventEmitter class. The on() method takes two arguments: the name of the event to listen for, and a callback function that will be executed when the event is emitted.
myEmitter.on('hello', () => {
console.log('Hello, world!');
});
This code listens for an event named 'hello' using the myEmitter object, and when the event is emitted, it logs the message 'Hello, world!' to the console.
Removing Event Listeners
To remove an event listener, we can use the removeListener() method of the EventEmitter class. The removeListener() method takes two arguments: the name of the event to remove the listener from, and the listener function to remove.
const helloListener = () => {
console.log('Hello, world!');
};
myEmitter.on('hello', helloListener);
// Remove the helloListener function from the 'hello' event
myEmitter.removeListener('hello', helloListener);
This code attaches an event listener to the 'hello' event using the myEmitter object, and then removes the event listener using the removeListener() method.
Once
The once() method of the EventEmitter class is similar to the on() method, but it only listens for the event to be emitted once. After the event is emitted and the listener function is executed, the listener is automatically removed.
myEmitter.once('hello', () => {
console.log('Hello, world!');
});
// Emit the 'hello' event
myEmitter.emit('hello');
// The following line won't log anything because the listener was removed after it was executed
myEmitter.emit('hello');
This code listens for the 'hello' event using the once() method, emits the event once using the emit() method, and then tries to emit the event again. The second emit() call won't log anything because the listener was removed after it.
example:
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
// Register the listener using the 'prependListener' method
myEmitter.prependListener('greet', () => {
console.log('Hello, world!');
});
// Register another listener using the 'on' method
myEmitter.on('greet', (name) => {
console.log(`Hello, ${name}!`);
});
// Emit the 'greet' event twice, with different arguments
myEmitter.emit('greet', 'John');
myEmitter.emit('greet', 'Jane');
/*
Output:
Hello, world!
Hello, John!
Hello, world!
Hello, Jane!
*/
12. Streams and Buffer
Streams
Streams are a way to read and write data in small chunks, rather than loading entire files or data sets into memory at once. They are used in Node.js to read and write data to and from files, network sockets, and other sources of data.
Streams are implemented in Node.js as instances of the stream.Readable and stream.Writable classes. There are also other classes such as stream.Duplex and stream.Transform that combine both readable and writable streams.
const fs = require('fs');
const stream = fs.createReadStream('example.txt');
stream.on('data', (chunk) => {
console.log(chunk);
});
stream.on('end', () => {
console.log('Finished reading file');
});
In this example, we create a readable stream using the fs.createReadStream() method, which reads data from a file and returns a stream object. We then attach event listeners to the stream object for the 'data' and 'end' events. The 'data' event is triggered whenever new data is available to be read from the stream, and we log each chunk of data to the console. The 'end' event is triggered when the stream has finished reading all of the data.
Buffers
Buffers are used to represent and manipulate binary data in Node.js. They are essentially fixed-size chunks of memory that can be used to store and manipulate binary data. Buffers are used extensively in Node.js for handling network communication, file I/O, and other types of data processing.
Buffers can be created in several ways, such as from a string, an array, or by allocating a specific amount of memory.
const buffer = Buffer.alloc(8);
buffer.writeUInt32BE(0xfeedface, 0);
buffer.writeUInt32BE(0xdeadbeef, 4);
console.log(buffer.toString('hex')); // feedfacedeadbeef
In this example, we create a new buffer with a length of 8 bytes using the Buffer.alloc() method. We then use the writeUInt32BE() method to write two 32-bit unsigned integers to the buffer, starting at byte offset 0 and 4, respectively. Finally, we log the contents of the buffer as a hexadecimal string using the toString() method.
13. Introduction to NPM
NPM (short for Node Package Manager) is a package manager for Node.js that allows you to easily install, manage, and share third-party libraries and modules. It is the default package manager for Node.js, and it comes pre-installed with Node.js.
NPM Commands
NPM has a variety of commands that can be used to manage packages and modules.
npm init: This command initializes a new Node.js project and creates a package.json file that contains metadata about the project and its dependencies.
npm install: This command installs packages and modules from the NPM registry. You can specify the package name and version as arguments, or you can specify them in the package.json file and run npm install without any arguments to install all the dependencies listed in the package.json file.
npm uninstall: This command uninstalls packages and modules that are installed in the project. You can specify the package name as an argument, or you can remove the package from the package.json file and run npm install to remove it.
npm update: This command updates the installed packages and modules to their latest version.
npm search: This command searches the NPM registry for packages and modules that match a given keyword.
npm publish: This command publishes your own package or module to the NPM registry.
NPM Packages
NPM packages are collections of files and code that are designed to be installed and used in Node.js projects. They can include JavaScript files, configuration files, documentation, and other resources.
When you install an NPM package, its files and code are downloaded and installed in a 'node_modules' directory in your project. You can then import the package's code and use it in your own code.
NPM packages are published to the NPM registry, which is a public repository of packages and modules. You can search the registry for packages that meet your needs, and then install them in your projects using the npm install command (eg: npm install loadash, npm install express, etc.).
14. Installing and Managing Packages
If you want to install a specific version of a package, you can specify the version number using the '@' symbol. For example, to install version 2.1.1 of the 'axios' package, you can run
npm install axios@2.1.1
You can also install multiple packages at once by separating their names with spaces. For example, to install both 'express' and 'axios'
npm install express axios
Managing Packages
To view a list of all the packages installed in your project, you can use the 'npm ls' command. This will display a tree-like structure of all the installed packages and their dependencies.
If you want to update a package to its latest version, you can use the npm update command followed by the name of the package. For example, to update the express package to its latest version, you can run
npm update express
If you want to update all the packages in your project to their latest versions, you can use the 'npm update' command without specifying a package name.
npm update
To remove a package from your project, you can use the 'npm uninstall' command followed by the name of the package. For example, to uninstall the axios package, you can run
npm uninstall axios
15. Package.json file
The 'package.json' file is a configuration file that is used to specify various properties of an application or package. This file is used by the npm package manager to identify the project and manage its dependencies.
{
"name": "my-app",
"version": "1.0.0",
"description": "My awesome application",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^4.17.1",
"body-parser": "^1.19.0"
}
}
In this example, we have defined the following properties
name: The name of the project or package.
version: The version number of the project or package.
description: A brief description of the project or package.
main: The entry point for the application or package.
scripts: A set of scripts that can be run using the npm run command.
dependencies: A list of dependencies required by the application or package.
16. Event loop and Asynchronous Programming
Asynchronus programming
Asynchronous programming is a programming paradigm that allows for the execution of multiple tasks concurrently. In Node.js, asynchronous programming is used extensively to allow for non-blocking I/O operations. Rather than waiting for a task to complete before moving on to the next one, Node.js can initiate multiple tasks and execute them concurrently. This allows for more efficient use of system resources and can improve the overall performance of an application.
const fs = require('fs');
fs.readFile('myfile.txt', 'utf8', function (err, data) {
if (err) throw err;
console.log(data);
});
console.log('Reading file...');
In this example, we use the fs.readFile() method to read the contents of a file asynchronously. When the file is read, the specified callback function is executed, and the contents of the file are printed to the console. In the meantime, the console.log('Reading file...') statement is executed immediately, rather than waiting for the file to be read.
Event Loops
The event loop is the mechanism by which Node.js handles I/O operations. The event loop continuously checks for events and executes any associated callback functions. When an I/O operation is initiated, it is added to a queue, and the event loop will continue to check the queue for any completed operations. Once an operation is completed, the associated callback function is added to the event loop for execution. This allows Node.js to handle a large number of I/O operations in a non-blocking way.
console.log('Starting...');
setTimeout(function() {
console.log('1 second passed.');
}, 1000);
setTimeout(function() {
console.log('2 seconds passed.');
}, 2000);
setTimeout(function() {
console.log('3 seconds passed.');
}, 3000);
console.log('End.');
/*
Output:
Starting...
End.
1 second passed.
2 seconds passed.
3 seconds passed.
*/
In this example, we use the setTimeout() function to delay the execution of some code. The first setTimeout() function waits for 1 second, the second waits for 2 seconds, and the third waits for 3 seconds. After each delay, a message is printed to the console.
As you can see, the console.log('Starting...') statement is executed immediately, followed by the setTimeout() functions. These functions are added to the event loop and are not executed immediately. Instead, they wait for the specified amount of time (in this case, 1, 2, and 3 seconds) before being added to the event loop for execution.
While the setTimeout() functions are waiting, the console.log('End.') statement is executed immediately, as it is not part of the event loop. Once the setTimeout() functions are added to the event loop, they are executed in the order that they were added. This results in the messages being printed to the console in the order of 1 second passed, 2 seconds passed, and 3 seconds passed.
17. Non-blocking I/O
Non-blocking I/O is a technique used in computer programming that allows multiple operations to be performed concurrently, without blocking each other. In Node.js, non-blocking I/O is achieved through the use of asynchronous functions and callbacks.
When a Node.js application makes an I/O request (such as reading from a file or making a network request), the application does not wait for the operation to complete. Instead, Node.js adds the request to a queue and continues executing the rest of the application code. When the I/O operation completes, Node.js retrieves the result and executes the callback function associated with the operation.
const fs = require('fs');
console.log('Starting...');
fs.readFile('example.txt', 'utf8', function(err, data) {
if (err) {
console.error(err);
} else {
console.log(data);
}
});
console.log('End.');
/*
Starting...
End.
Hello, world!
*/
In this Node.js example, we use the fs.readFile() function to read the contents of a file called example.txt. We provide a callback function as the last argument to fs.readFile(), which is executed once the file has been read.
The console.log('Starting...') statement is executed first, followed by the fs.readFile() function. Instead of blocking the rest of the application, the fs.readFile() function returns immediately and Node.js continues executing the rest of the code.
The console.log('End.') statement is executed before the fs.readFile() function completes, because fs.readFile() is a non-blocking I/O operation. When the file has been read, Node.js executes the callback function provided to fs.readFile(). This function logs the contents of the file to the console.
example
Suppose we have a Node.js server that needs to handle multiple requests simultaneously. For each request, the server needs to make a database query to fetch some data. Without non-blocking I/O, the server would have to wait for each query to complete before it can move on to the next request. This would make the server slow and unresponsive.
const http = require('http');
const mysql = require('mysql');
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'mydatabase'
});
const server = http.createServer((req, res) => {
connection.query('SELECT * FROM users', (err, results) => {
if (err) {
console.error(err);
res.statusCode = 500;
res.end('Internal Server Error');
} else {
res.setHeader('Content-Type', 'application/json');
res.statusCode = 200;
res.end(JSON.stringify(results));
}
});
});
server.listen(3000, () => {
console.log('Server listening on port 3000');
});
In this example, we create a Node.js server that listens on port 3000. Whenever a request is made to the server, it executes a database query to fetch all the users from a MySQL database. We use the mysql module to create a connection to the database and execute the query.
The connection.query() function is a non-blocking I/O operation, which means that it returns immediately and does not block the rest of the application. Once the query completes, Node.js executes the callback function provided to connection.query(), which sends the results back to the client.
18. Express
Express.js is a popular Node.js web application framework that allows developers to easily create robust and scalable web applications. It provides a simple and intuitive interface for handling HTTP requests, routing, middleware, and view rendering. Express.js is built on top of Node.js and leverages its non-blocking I/O model to provide fast and efficient performance.
To install Express.js, you need to have Node.js installed on your system. Once you have Node.js installed, you can use npm (Node Package Manager) to install Express.js.
npm install express
This will install the latest version of Express.js in your project. Once you have installed Express.js, lets create a basic "Hello World" web application using the following code
const express = require('express')
const app = express()
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(5000, () => {
console.log('app is listening on port 5000!')
})
1. First, we import the Express.js module using the 'require()' function and create a new Express.js application by calling 'express()'.
2. Next, we define a route for the root URL (/) using the app.get() method. When a GET request is made to this URL, we send the response "Hello World!" using the res.send() method.
3. Finally, we start the Express.js application by calling app.listen() and passing in the port number we want the application to listen on (in this case, 3000). We also log a message to the console to indicate that the application is running.
To run this code, save it to a file (e.g. app.js) and run the following command in your terminal or command prompt
node app.js
This will start the Express.js application and it will be accessible at http://localhost:5000. When you navigate to this URL in your web browser, you should see the message "Hello World!" displayed on the page.
19. Routing
In the context of an Express.js application, routing refers to determining how an application responds to a client request to a particular endpoint, which is associated with a specific HTTP method (GET, POST, PUT, DELETE, etc.).
In Express.js, routing is achieved using the 'express.Router()' method. This method returns an instance of a router that can be used to define application endpoints. The router instance can be associated with an Express.js application using the 'app.use()' method.
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello, World!');
});
app.listen(3000, () => {
console.log('Server started on port 3000');
});
In this example, we're defining a basic route for the root URL (/) of our application using the app.get() method. The app.get() method takes two arguments: the route and a callback function that is executed when the route is requested. In this case, we're sending a response of Hello, World! to the client.
The app.listen() method is used to start the server and listen for incoming requests. Here, we're telling the server to listen on port 3000.
Once the server is started, we can test our route by visiting http://localhost:3000 in a web browser.
example
const express = require('express');
const app = express();
// GET route for the root URL
app.get('/', function(req, res) {
res.send('Hello, World!');
});
// POST route for submitting a form
app.post('/submit-form', function(req, res) {
const name = req.body.name;
const email = req.body.email;
// Process the form data
res.send(`Thank you for submitting the form, ${name}! We will contact you at ${email}.`);
});
// PUT route for updating a user record
app.put('/users/:id', function(req, res) {
const userId = req.params.id;
// Update the user record in the database
res.send(`User with ID ${userId} updated successfully.`);
});
// DELETE route for deleting a user record
app.delete('/users/:id', function(req, res) {
const userId = req.params.id;
// Delete the user record from the database
res.send(`User with ID ${userId} deleted successfully.`);
});
// Start the server
app.listen(3000, function() {
console.log('Server started on port 3000');
});
In this example, we have defined routes for the root URL (/), a POST route for submitting a form (/submit-form), a PUT route for updating a user record (/users/:id), and a DELETE route for deleting a user record (/users/:id).
The GET route for the root URL simply sends back a "Hello, World!" message as the response.
The POST route for submitting a form expects the form data to be sent in the request body and processes it accordingly. It then sends a response back to the client with a personalized message.
The PUT and DELETE routes for updating and deleting a user record, respectively, expect the user ID to be included in the URL as a parameter (e.g., /users/123) and perform the respective actions in the database before sending a response back to the client.
Note: This is just a basic example, and in a real-world application, you would likely have many more routes and more complex logic within each route handler function.
20. Handling HTTP requests (GET, POST, PUT, DELETE)
To handle HTTP requests, we can create routes in our Express application. Each route can handle a specific HTTP method such as GET, POST, PUT, or DELETE.
GET
const express = require('express');
// Create an instance of the Express application
const app = express();
// Handle GET request for the root route
app.get('/', function(req, res) {
res.send('Hello World!');
});
// Start the server
app.listen(3000, function() {
console.log('Server listening on port 3000');
});
In this example, we have created a route for the root route using the app.get() method. This method takes two parameters: the route and a callback function to handle the request.
The callback function takes two parameters: the request object (req) and the response object (res). In this example, we are sending the response "Hello World!" using the res.send() method.
POST
const express = require('express');
// Create an instance of the Express application
const app = express();
// Handle POST request for the root route
app.post('/', function(req, res) {
res.send('Got a POST request');
});
// Start the server
app.listen(3000, function() {
console.log('Server listening on port 3000');
});
In this example, we have created a route for the root route using the app.post() method. This method takes two parameters: the route and a callback function to handle the request.
The callback function takes two parameters: the request object (req) and the response object (res). In this example, we are sending the response "Got a POST request" using the res.send() method.
PUT
const express = require('express');
// Create an instance of the Express application
const app = express();
// Handle PUT request for the root route
app.put('/', function(req, res) {
res.send('Got a PUT request');
});
// Start the server
app.listen(3000, function() {
console.log('Server listening on port 3000');
});
In this example, we have created a route for the root route using the app.put() method. This method takes two parameters: the route and a callback function to handle the request.
The callback function takes two parameters: the request object (req) and the response object (res). In this example, we are sending the response "Got a PUT request" using the res.send() method.
DELETE
const express = require('express');
// Create an instance of the Express application
const app = express();
// Handle DELETE request for the root route
app.delete('/', function(req, res) {
res.send('Got a DELETE request');
});
// Start the server
app.listen(3000, function() {
console.log('Server listening on port 3000');
});
In this example, we have created a route for the root route using the app.delete() method. This method takes two parameters: the route and a callback function to handle the request.
The callback function takes two parameters: the request object (req) and the response object (res).
21. Middleware
Middleware in Express.js is a function that can modify the request and response objects, execute additional code, and pass the request to the next middleware function in the chain. Middleware functions can be used to perform tasks like parsing request bodies, handling authentication, logging, and much more.
const express = require('express');
const app = express();
// custom middleware
const logMiddleware = (req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
next(); // pass the request to the next middleware function
};
app.use(logMiddleware);
app.get('/', (req, res) => {
res.send('Hello, world!');
});
app.listen(5000, () => {
console.log('Server listening on port 5000');
});
In the above example, we define a middleware function called logMiddleware that logs the current date and time, the HTTP method and the URL of the incoming request. Then, we use the app.use() method to register this middleware function for all routes.
When we send a GET request to the root route (/), the middleware function gets executed and logs the request details to the console before passing the request to the next middleware function (app.get() in this case). Finally, the route handler sends the response back to the client with the message "Hello, world!".
22. Body Parser
Body parser is a middleware module that is used to extract the entire body portion of an incoming request stream and exposes it on req.body. It can be used to parse various types of request data such as JSON, URL-encoded, text, raw and XML.
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json()); // parse JSON-encoded request bodies
app.post('/users', (req, res) => {
const { name, email } = req.body; // extract name and email from request body
// save the user to the database...
res.status(201).send('User created successfully');
});
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
In the above example, we first import and use the body-parser middleware by calling app.use(bodyParser.json()). This instructs the middleware to parse any incoming request with a JSON payload and store it in the req.body property.
We then define a POST route /users, where we extract the name and email fields from the request body using destructuring. Finally, we save the user to the database and send a response with status 201 and a success message.
Note that there are different types of request bodies that can be parsed by body-parser, such as 'urlencoded', 'text', and 'raw'. You can specify the type of the incoming request body by calling the appropriate body-parser method in app.use().
23. Static Files
Static files refer to files such as images, CSS, and JavaScript files that do not change dynamically and are served directly to the client. These files are typically stored in a public directory in the server and are accessible to the client through a URL.
In Express.js, serving static files is made easy using the express.static middleware function. T
const express = require('express');
const app = express();
// serve static files from the public directory
app.use(express.static('public'));
// start the server
app.listen(3000, () => {
console.log('Server started on port 3000');
});
In this example, the express.static middleware function is used to serve static files from the public directory. The files in this directory can be accessed by clients by using the URL path relative to the public directory. For example, if there is a file named index.html in the public directory, it can be accessed by the client using the URL http://localhost:3000/index.html.
Note that the directory name passed to express.static is relative to the root directory of the application. So if the public directory is located in a subdirectory of the root directory, the directory name should include the path to the subdirectory. For example, if the public directory is located in the static subdirectory of the root directory, the middleware should be defined like this
app.use(express.static('static/public'));
This will serve the static files from the public directory inside the static directory.
24. Template engines
Template engines are used to generate dynamic HTML pages in web applications. They allow developers to define reusable HTML templates with placeholders that are filled with dynamic data at runtime. This makes it easier to build web applications that have consistent layouts and styling, while also being able to generate dynamic content on the server-side.
Express.js supports a number of popular template engines including EJS, Pug (formerly known as Jade), Handlebars, and Mustache. These engines provide a simple syntax for defining templates, and can be easily integrated into an Express.js application.
To use a template engine in an Express.js application, you need to install the engine using NPM, and then configure your application to use the engine.
1. Install EJS using NPM
npm install ejs --save
2. Configure your Express.js application to use EJS
const express = require('express');
const app = express();
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
app.get('/', (req, res) => {
res.render('index', { title: 'Welcome to my website', message: 'This is my first website using Express.js and EJS' });
});
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
In this example, we set the view engine to ejs using app.set('view engine', 'ejs'). We also set the views directory using app.set('views', __dirname + '/views'). This tells Express.js where to find the template files.
The res.render method is used to render the index.ejs template and pass in the data for the placeholders. The data is passed in as an object with key-value pairs.
example of the index.ejs template
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h1><%= message %></h1>
</body>
</html>
25. Error Handling
The basic idea is to define an error-handling middleware function with four arguments: 'err', 'req', 'res', and 'next'. The error-handling middleware function should be defined last in the middleware chain.
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something went wrong!');
});
In this example, app.use() is used to define the middleware function. The function takes four arguments, with the first one being the error object err. The console.error() function is used to log the error stack to the console. The res.status() function is used to set the status code of the response to 500 (Internal Server Error). The res.send() function is used to send a generic error message to the client.
To use this error-handling middleware function, you can simply call the next() function with an error object in any middleware function.
example
app.get('/user/:id', (req, res, next) => {
const id = req.params.id;
if (id === '0') {
next(new Error('Invalid user ID'));
} else {
res.send(`User ID: ${id}`);
}
});
In this example, the next() function is called with an error object if the user ID is 0. When the error object is passed to the next() function, it will skip all the remaining middleware functions and jump directly to the error-handling middleware function.
26. Connetion to MySQL Database
Connecting to MySQL database from a Node.js application involves installing the MySQL driver for Node.js and then using it to create a connection to the database. Here is a step-by-step tutorial on how to connect to a MySQL database from a Node.js application:
Step 1: Install the MySQL driver for Node.js using NPM
Open your terminal and run the following command to install the mysql package from NPM
npm install mysql
Step 2: Create a connection to the MySQL database
In your Node.js application, require the mysql package and use the createConnection method to create a connection to the MySQL database.
const mysql = require('mysql');
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'mydatabase'
});
connection.connect((error) => {
if (error) {
console.error('Error connecting to MySQL database: ' + error.stack);
return;
}
console.log('Connected to MySQL database with connection id ' + connection.threadId);
});
In the above example, replace the host, user, password, and database properties with your MySQL server details.
Step 3: Execute queries on the MySQL database
Once you have a connection to the MySQL database, you can use it to execute queries on the database using the query method of the connection object.
const mysql = require('mysql');
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'mydatabase'
});
connection.connect((error) => {
if (error) {
console.error('Error connecting to MySQL database: ' + error.stack);
return;
}
console.log('Connected to MySQL database with connection id ' + connection.threadId);
connection.query('SELECT * FROM users', (error, results, fields) => {
if (error) {
console.error('Error executing query: ' + error.stack);
return;
}
console.log('Results:', results);
});
});
In the above example, the query method is used to execute a SELECT statement on the users table in the mydatabase database. The callback function is called with the error (if any), the results of the query, and metadata about the fields in the results.
Step 4: Close the connection to the MySQL database
When you are done using the connection to the MySQL database, you should close the connection using the end method of the connection object.
const mysql = require('mysql');
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'mydatabase'
});
connection.connect((error) => {
if (error) {
console.error('Error connecting to MySQL database: ' + error.stack);
return;
}
console.log('Connected to MySQL database with connection id ' + connection.threadId);
connection.end((error) => {
if (error) {
console.error('Error closing connection to MySQL database: ' + error.stack);
return;
}
console.log('Connection to MySQL database closed.');
});
});
In the above example, the 'end' method is used to close the connection to the MySQL database. The callback function is called with the error (if any) when the connection is closed.
That's it! Now you know how to connect to a MySQL database from a Node.js application and execute queries on the database.
27. Connetion to MongoDB Database
To connect to a MongoDB database in a Node.js application, we can use the mongodb package.
Step 1: Install the 'mongodb' package using npm
npm install mongodb
Step 2: Import the mongodb package and create a MongoClient object
const { MongoClient } = require('mongodb');
const uri = 'mongodb://localhost:27017/mydb';
const client = new MongoClient(uri);
Note: Replace localhost:27017 with the address of your MongoDB server and mydb with the name of your database.
Step 3: Connect to the MongoDB server
await client.connect();
console.log('Connected to MongoDB');
Step 4: Access a database and collection
const db = client.db('mydb');
const collection = db.collection('mycollection');
Note: Replace 'mydb' with the name of your database and mycollection with the name of your collection.
Step 5: Perform operations on the collection
For example, to insert a document
const document = { name: 'John Doe', age: 30 };
const result = await collection.insertOne(document);
console.log(`Inserted document with id ${result.insertedId}`);
Step 6: Close the connection to the server when finished
await client.close();
console.log('Connection to MongoDB closed');
28. CRUD Operations using MySQL Database
First, we need to install mysql2 module in our Node.js application using npm
npm install mysql2
To establish a connection to a MySQL database, we need to create a connection object using createConnection method provided by mysql2 module.
const mysql = require('mysql2');
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'mydb'
});
connection.connect((err) => {
if (err) throw err;
console.log('Connected to MySQL database!');
});
Create
To create a new record in a MySQL database, we can use query method provided by mysql2 module.
const newRecord = { name: 'John Doe', age: 30, email: 'john.doe@example.com' };
connection.query('INSERT INTO mytable SET ?', newRecord, (err, result) => {
if (err) throw err;
console.log('New record added:', result.insertId);
});
In the above example, we created a new record with the required data fields using an object literal newRecord. Then, we used query method to insert the new record into mytable. We passed the INSERT SQL statement and the new record object as parameters to the query method. When the query method completes successfully, it will return a result object containing the insertId property, which represents the unique identifier of the new record.
Read
To retrieve data from a MySQL database, we can use query method with a SELECT SQL statement.
connection.query('SELECT * FROM mytable', (err, results) => {
if (err) throw err;
console.log('Retrieved records:', results);
});
In the above example, we used query method to retrieve all records from mytable. When the query method completes successfully, it will return a result object containing the retrieved records in the results property.
Update
To update an existing record in a MySQL database, we can use query method with an UPDATE SQL statement.
const idToUpdate = 1;
const updatedRecord = { age: 35 };
connection.query('UPDATE mytable SET ? WHERE id = ?', [updatedRecord, idToUpdate], (err, result) => {
if (err) throw err;
console.log('Updated record:', result.affectedRows);
});
Delete
To delete data from a MySQL database using Node.js, we can use the DELETE statement.
const sql = "DELETE FROM customers WHERE id = 1";
connection.query(sql, (err, result) => {
if (err) throw err;
console.log(result.affectedRows + " record(s) deleted");
});
The DELETE statement to delete a record from the customers table where the id is equal to 1. Finally, we use the query method of the connection to execute the statement and log the number of affected rows.
29. CRUD Operations using MongoDB Database
Creating a new document
const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017';
const client = new MongoClient(url, { useUnifiedTopology: true });
client.connect((err) => {
if (err) throw err;
const db = client.db('mydb');
const collection = db.collection('mycollection');
const newDocument = { name: 'John Doe', age: 30, email: 'john.doe@example.com' };
collection.insertOne(newDocument, (err, result) => {
if (err) throw err;
console.log('New document added:', result.insertedId);
client.close();
});
});
Reading documents
const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017';
const client = new MongoClient(url, { useUnifiedTopology: true });
client.connect((err) => {
if (err) throw err;
const db = client.db('mydb');
const collection = db.collection('mycollection');
// find all documents in the collection
collection.find({}).toArray((err, documents) => {
if (err) throw err;
console.log('All documents:', documents);
client.close();
});
// find documents that match a specific condition
collection.find({ name: 'John Doe' }).toArray((err, documents) => {
if (err) throw err;
console.log('John Doe documents:', documents);
client.close();
});
});
Updating documents
const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017';
const client = new MongoClient(url, { useUnifiedTopology: true });
client.connect((err) => {
if (err) throw err;
const db = client.db('mydb');
const collection = db.collection('mycollection');
// update a document that matches a specific condition
const condition = { name: 'John Doe' };
const update = { $set: { age: 40 } };
collection.updateOne(condition, update, (err, result) => {
if (err) throw err;
console.log('Document updated:', result.modifiedCount);
client.close();
});
});
Deleting documents
const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017';
const client = new MongoClient(url, { useUnifiedTopology: true });
client.connect((err) => {
if (err) throw err;
const db = client.db('mydb');
const collection = db.collection('mycollection');
// delete a document that matches a specific condition
const condition = { name: 'John Doe' };
collection.deleteOne(condition, (err, result) => {
if (err) throw err;
console.log('Document deleted:', result.deletedCount);
client.close();
});
});