Learn Node.js, the versatile JavaScript runtime environment, to unlock a world of opportunities in web development. At learns.edu.vn, we believe mastering Node.js empowers you to build scalable, high-performance applications. Dive into this comprehensive guide to discover the power of Node.js and how it can transform your coding skills. This guide covers the fundamental concepts, key features, and practical applications of Node.js.
1. Understanding Node.js
1.1. What is Node.js?
Node.js is an open-source, cross-platform JavaScript runtime environment that executes JavaScript code server-side. Unlike traditional JavaScript, which runs in a web browser, Node.js allows developers to use JavaScript to write command-line tools and server-side scripts. This capability enables the creation of dynamic web pages before they are sent to the user’s web browser.
- Definition: Node.js is built on Chrome’s V8 JavaScript engine, providing a runtime environment that allows JavaScript to be executed outside of browsers.
- Key Features:
- Asynchronous and Event-Driven: Handles multiple operations concurrently without blocking, making it highly efficient.
- Single-Threaded: Uses a single-threaded event loop model, which can handle a large number of concurrent requests.
- Non-Blocking I/O: Performs I/O operations asynchronously, improving performance and scalability.
- Cross-Platform: Runs on various operating systems, including Windows, Linux, and macOS.
- NPM (Node Package Manager): Provides access to a vast ecosystem of open-source libraries and tools.
- JavaScript Everywhere: Enables developers to use JavaScript for both front-end and back-end development, promoting code reuse and consistency.
1.2. Why Learn Node.js?
Learning Node.js offers numerous advantages for developers. Here’s why it’s worth your time and effort:
- Full-Stack JavaScript: Use JavaScript for both client-side and server-side development, reducing the need to learn multiple languages. This capability can significantly improve development speed and efficiency.
- High Performance: Node.js’s non-blocking, event-driven architecture makes it highly efficient and scalable, ideal for building real-time applications and APIs. Studies have shown that Node.js applications can handle more concurrent requests compared to traditional server-side technologies like Apache. For instance, a benchmark test by Joyent found that Node.js could handle twice as many requests per second as Apache.
- Large and Active Community: Benefit from a vast ecosystem of open-source libraries and frameworks available through NPM, making development faster and more efficient. The Node.js community is continuously growing, providing ample resources, tutorials, and support for developers.
- Versatile Use Cases: Build a wide range of applications, including web servers, real-time applications, microservices, and command-line tools. Node.js is suitable for various industries, including e-commerce, social media, and IoT.
- Career Opportunities: Node.js developers are in high demand, with excellent job prospects and competitive salaries. According to a report by the U.S. Bureau of Labor Statistics, the demand for web developers, including those skilled in Node.js, is projected to grow 13 percent from 2020 to 2030, faster than the average for all occupations.
- Simplified Development: The use of JavaScript across the entire stack simplifies development workflows and reduces the learning curve for front-end developers transitioning to back-end development. This unified approach can lead to more cohesive and efficient teams.
1.3. Key Concepts of Node.js
To effectively learn Node.js, it’s essential to understand its core concepts:
- Event Loop: The heart of Node.js, managing asynchronous operations by continuously monitoring the call stack and task queue. The event loop enables Node.js to handle multiple concurrent requests efficiently by delegating tasks to the operating system and processing the results when they become available.
- Modules: Reusable blocks of code that encapsulate specific functionality, allowing for modular and organized development. Node.js has a built-in module system that allows developers to import and export modules, promoting code reuse and maintainability.
- NPM (Node Package Manager): The package manager for Node.js, providing access to a vast repository of open-source libraries and tools. NPM simplifies the process of installing, updating, and managing dependencies, allowing developers to focus on writing code rather than managing infrastructure.
- Asynchronous Programming: Writing code that doesn’t block the main thread, using callbacks, promises, and async/await to handle asynchronous operations. Asynchronous programming is crucial for building scalable and responsive Node.js applications.
- Streams: A sequence of data made available over time, used for handling large amounts of data efficiently. Streams allow Node.js to process data in chunks, reducing memory consumption and improving performance.
2. Setting Up Your Node.js Environment
2.1. Installing Node.js
Before you can start learning Node.js, you need to install it on your system. Here’s how:
- Download Node.js:
- Visit the official Node.js website: Node.js Downloads.
- Choose the appropriate installer for your operating system (Windows, macOS, or Linux).
- Download the LTS (Long Term Support) version for stability or the Current version for the latest features.
- Installation Process:
- Windows:
- Run the downloaded
.msi
installer. - Follow the on-screen instructions, accepting the license agreement and default settings.
- Ensure the option to add Node.js to your PATH environment variable is selected.
- Run the downloaded
- macOS:
- Run the downloaded
.pkg
installer. - Follow the on-screen instructions, accepting the license agreement and default settings.
- Run the downloaded
- Linux:
- Use a package manager such as
apt
(Debian/Ubuntu) oryum
(CentOS/RHEL). - For example, on Ubuntu:
- Use a package manager such as
- Windows:
<span><span>sudo</span><span> apt</span><span> update</span></span> <span><span>sudo</span><span> apt</span><span> install</span><span> nodejs</span></span> <span><span>sudo</span><span> apt</span><span> install</span><span> npm</span></span>
- Verify Installation:
- Open a new terminal or command prompt.
- Type the following commands to check the installed versions of Node.js and NPM:
<span><span>node</span><span> -v</span></span> <span><span>npm</span><span> -v</span></span>
* If the installation was successful, you should see the version numbers printed in the terminal.
2.2. Setting Up a Development Environment
A good development environment can significantly improve your coding experience. Here are the recommended tools and settings:
- Text Editor or IDE (Integrated Development Environment):
- Visual Studio Code (VS Code): A popular, free, and highly customizable editor with excellent support for Node.js. It offers features like IntelliSense, debugging, and integrated Git support.
- Sublime Text: A lightweight and powerful editor with a wide range of plugins.
- Atom: A customizable, open-source editor developed by GitHub.
- WebStorm: A commercial IDE specifically designed for JavaScript development, offering advanced features like code completion, refactoring, and debugging.
- NPM (Node Package Manager):
- NPM comes bundled with Node.js and is used to manage project dependencies.
- Update NPM to the latest version using:
<span><span>npm</span><span> install</span><span> -g</span><span> npm@latest</span></span>
- Package.json:
- A file in your project directory that contains metadata about your project, including dependencies, scripts, and version information.
- Create a
package.json
file using:
<span><span>npm</span><span> init</span><span> -y</span></span>
- Git:
- A version control system for tracking changes to your code.
- Initialize a Git repository in your project directory using:
<span><span>git</span><span> init</span></span>
- Debugging Tools:
- Node.js comes with a built-in debugger that can be accessed using the
node inspect
command. - VS Code offers a user-friendly debugging interface for Node.js applications.
- Node.js comes with a built-in debugger that can be accessed using the
2.3. Creating Your First Node.js Application
Let’s create a simple “Hello, World ” application to ensure your environment is set up correctly:
- Create a New Directory:
<span><span>mkdir</span><span> hello-node</span></span> <span><span>cd</span><span> hello-node</span></span>
- Create a File Named
app.js
:- Open
app.js
in your text editor and add the following code:
- Open
<span><span>const</span><span> http </span><span>=</span><span> require</span><span>(</span><span>'http'</span><span>);</span><span>const</span><span> hostname </span><span>=</span><span> '127.0.0.1'</span><span>;</span><span>const</span><span> port </span><span>=</span><span> 3000</span><span>;</span><span>const</span><span> server </span><span>=</span><span> http.createServer</span><span>((</span><span>req</span><span>,</span><span> res</span><span>)</span><span> =></span><span>{</span><span>res.statusCode </span><span>=</span><span> 200</span><span>;</span><span>res.setHeader</span><span>(</span><span>'Content-Type'</span><span>,</span><span> 'text/plain'</span><span>);</span><span>res.end</span><span>(</span><span>'Hello, World!n'</span><span>);</span><span>});</span><span>server.listen</span><span>(</span><span>port</span><span>,</span><span> hostname</span><span>,</span><span> () </span><span>=></span><span>{</span><span>console.log</span><span>(</span><span>`Server running at http://${hostname}:${port}/`</span><span>);</span><span>});</span>
- Run the Application:
- Open your terminal, navigate to the
hello-node
directory, and run:
- Open your terminal, navigate to the
<span><span>node</span><span> app.js</span></span>
- View the Output:
- Open your web browser and navigate to
http://localhost:3000
. - You should see “Hello, World ” displayed in your browser.
- Open your web browser and navigate to
3. Core Modules in Node.js
Node.js comes with a set of built-in modules that provide essential functionalities. Understanding these core modules is crucial for effective Node.js development:
3.1. HTTP Module
The http
module is used for creating HTTP servers and clients. It allows you to handle HTTP requests and responses, making it fundamental for building web applications and APIs:
- Creating a Server:
<span><span>const</span><span> http </span><span>=</span><span> require</span><span>(</span><span>'http'</span><span>);</span><span>const</span><span> server </span><span>=</span><span> http.createServer</span><span>((</span><span>req</span><span>,</span><span> res</span><span>)</span><span> =></span><span>{</span><span>res.statusCode </span><span>=</span><span> 200</span><span>;</span><span>res.setHeader</span><span>(</span><span>'Content-Type'</span><span>,</span><span> 'text/plain'</span><span>);</span><span>res.end</span><span>(</span><span>'Hello, World!n'</span><span>);</span><span>});</span><span>server.listen</span><span>(</span><span>3000</span><span>,</span><span> () </span><span>=></span><span>{</span><span>console.log</span><span>(</span><span>'Server running at http://localhost:3000/'</span><span>);</span><span>});</span>
- Making a Request:
<span><span>const</span><span> http </span><span>=</span><span> require</span><span>(</span><span>'http'</span><span>);</span><span>const</span><span> options </span><span>=</span><span>{</span><span>hostname</span><span>:</span><span> 'www.example.com'</span><span>,</span><span>port</span><span>:</span><span> 80</span><span>,</span><span>path</span><span>:</span><span> '/'</span><span>,</span><span>method</span><span>:</span><span> 'GET'</span><span>};</span><span>const</span><span> req </span><span>=</span><span> http.request</span><span>(</span><span>options</span><span>,</span><span> (</span><span>res</span><span>)</span><span> =></span><span>{</span><span>console.log</span><span>(</span><span>`statusCode: ${res.statusCode}`</span><span>);</span><span>res.on</span><span>(</span><span>'data'</span><span>,</span><span> (</span><span>chunk</span><span>)</span><span> =></span><span>{</span><span>console.log</span><span>(</span><span>`Body: ${chunk}`</span><span>);</span><span>});</span><span>});</span><span>req.on</span><span>(</span><span>'error'</span><span>,</span><span> (</span><span>error</span><span>)</span><span> =></span><span>{</span><span>console.error</span><span>(</span><span>error</span><span>);</span><span>});</span><span>req.end</span><span>();</span>
3.2. File System (fs) Module
The fs
module provides methods for interacting with the file system. It allows you to read, write, update, and delete files:
- Reading a File:
<span><span>const</span><span> fs </span><span>=</span><span> require</span><span>(</span><span>'fs'</span><span>);</span><span>fs.readFile</span><span>(</span><span>'example.txt'</span><span>,</span><span> 'utf8'</span><span>,</span><span> (</span><span>err</span><span>,</span><span> data</span><span>)</span><span> =></span><span>{</span><span>if</span><span> (err)</span><span>{</span><span>console.error</span><span>(</span><span>err</span><span>);</span><span>return</span><span>;</span><span>}</span><span>console.log</span><span>(</span><span>data</span><span>);</span><span>});</span>
- Writing to a File:
<span><span>const</span><span> fs </span><span>=</span><span> require</span><span>(</span><span>'fs'</span><span>);</span><span>const</span><span> content </span><span>=</span><span> 'Hello, Node.js!'</span><span>;</span><span>fs.writeFile</span><span>(</span><span>'example.txt'</span><span>,</span><span> content</span><span>,</span><span> (</span><span>err</span><span>)</span><span> =></span><span>{</span><span>if</span><span> (err)</span><span>{</span><span>console.error</span><span>(</span><span>err</span><span>);</span><span>}</span><span>console.log</span><span>(</span><span>'File written successfully'</span><span>);</span><span>});</span>
3.3. Path Module
The path
module provides utilities for working with file and directory paths. It helps you to construct, normalize, and manipulate paths in a platform-independent way:
- Joining Paths:
<span><span>const</span><span> path </span><span>=</span><span> require</span><span>(</span><span>'path'</span><span>);</span><span>const</span><span> filePath </span><span>=</span><span> path.join</span><span>(</span><span>'/Users/John'</span><span>,</span><span> 'documents'</span><span>,</span><span> 'example.txt'</span><span>);</span><span>console.log</span><span>(</span><span>filePath</span><span>);</span><span>// Output: /Users/John/documents/example.txt</span>
- Getting Path Information:
<span><span>const</span><span> path </span><span>=</span><span> require</span><span>(</span><span>'path'</span><span>);</span><span>const</span><span> filePath </span><span>=</span><span> '/Users/John/documents/example.txt'</span><span>;</span><span>console.log</span><span>(</span><span>path.basename</span><span>(</span><span>filePath</span><span>));</span><span>// Output: example.txt</span><span>console.log</span><span>(</span><span>path.dirname</span><span>(</span><span>filePath</span><span>));</span><span>// Output: /Users/John/documents</span><span>console.log</span><span>(</span><span>path.extname</span><span>(</span><span>filePath</span><span>));</span><span>// Output: .txt</span>
3.4. OS Module
The os
module provides operating system-related utility methods. It allows you to retrieve information about the operating system, such as the hostname, CPU architecture, and memory:
- Getting OS Information:
<span><span>const</span><span> os </span><span>=</span><span> require</span><span>(</span><span>'os'</span><span>);</span><span>console.log</span><span>(</span><span>'Platform:'</span><span>,</span><span> os.platform</span><span>());</span><span>console.log</span><span>(</span><span>'Architecture:'</span><span>,</span><span> os.arch</span><span>());</span><span>console.log</span><span>(</span><span>'Free memory:'</span><span>,</span><span> os.freemem</span><span>());</span><span>console.log</span><span>(</span><span>'Total memory:'</span><span>,</span><span> os.totalmem</span><span>());</span>
3.5. URL Module
The url
module provides utilities for parsing and formatting URLs. It allows you to extract different parts of a URL, such as the protocol, hostname, and query parameters:
- Parsing a URL:
<span><span>const</span><span> url </span><span>=</span><span> require</span><span>(</span><span>'url'</span><span>);</span><span>const</span><span> urlString </span><span>=</span><span> 'https://www.example.com/path?query=value#hash'</span><span>;</span><span>const</span><span> parsedUrl </span><span>=</span><span> url.parse</span><span>(</span><span>urlString</span><span>,</span><span> true</span><span>);</span><span>console.log</span><span>(</span><span>'Protocol:'</span><span>,</span><span> parsedUrl.protocol</span><span>);</span><span>console.log</span><span>(</span><span>'Hostname:'</span><span>,</span><span> parsedUrl.hostname</span><span>);</span><span>console.log</span><span>(</span><span>'Pathname:'</span><span>,</span><span> parsedUrl.pathname</span><span>);</span><span>console.log</span><span>(</span><span>'Query:'</span><span>,</span><span> parsedUrl.query</span><span>);</span><span>console.log</span><span>(</span><span>'Hash:'</span><span>,</span><span> parsedUrl.hash</span><span>);</span>
These core modules are the building blocks of many Node.js applications. Mastering them will enable you to build a wide range of applications, from simple web servers to complex APIs.
4. Asynchronous Programming in Node.js
4.1. Understanding Asynchronous Operations
Asynchronous programming is a crucial aspect of Node.js. It allows your application to perform multiple tasks concurrently without blocking the main thread. This is particularly important for I/O-bound operations, such as reading files, making network requests, and querying databases.
- Synchronous vs. Asynchronous:
- Synchronous: Operations are executed one at a time, in a sequential manner. Each operation must complete before the next one can start. This can lead to blocking if an operation takes a long time to complete.
- Asynchronous: Operations are executed concurrently, allowing the application to continue processing other tasks while waiting for an operation to complete. This prevents blocking and improves performance.
4.2. Callbacks
Callbacks are a common way to handle asynchronous operations in Node.js. A callback is a function that is passed as an argument to another function and is executed when the asynchronous operation completes:
- Example:
<span><span>const</span><span> fs </span><span>=</span><span> require</span><span>(</span><span>'fs'</span><span>);</span><span>fs.readFile</span><span>(</span><span>'example.txt'</span><span>,</span><span> 'utf8'</span><span>,</span><span> (</span><span>err</span><span>,</span><span> data</span><span>)</span><span> =></span><span>{</span><span>if</span><span> (err)</span><span>{</span><span>console.error</span><span>(</span><span>err</span><span>);</span><span>return</span><span>;</span><span>}</span><span>console.log</span><span>(</span><span>data</span><span>);</span><span>});</span><span>console.log</span><span>(</span><span>'Reading the file...'</span><span>);</span>
- Callback Hell:
- Using nested callbacks for multiple asynchronous operations can lead to “callback hell,” which makes the code difficult to read and maintain.
4.3. Promises
Promises provide a more structured way to handle asynchronous operations and avoid callback hell. A promise represents the eventual completion (or failure) of an asynchronous operation and allows you to chain multiple operations together:
- Creating a Promise:
<span><span>const</span><span> fs </span><span>=</span><span> require</span><span>(</span><span>'fs'</span><span>);</span><span>function</span><span> readFilePromise</span><span>(</span><span>filePath</span><span>)</span><span>{</span><span>return</span><span> new</span><span> Promise</span><span>((</span><span>resolve</span><span>,</span><span> reject</span><span>)</span><span> =></span><span>{</span><span>fs.readFile</span><span>(</span><span>filePath</span><span>,</span><span> 'utf8'</span><span>,</span><span> (</span><span>err</span><span>,</span><span> data</span><span>)</span><span> =></span><span>{</span><span>if</span><span> (err)</span><span>{</span><span>reject</span><span>(</span><span>err</span><span>);</span><span>return</span><span>;</span><span>}</span><span>resolve</span><span>(</span><span>data</span><span>);</span><span>});</span><span>});</span><span>}</span><span>readFilePromise</span><span>(</span><span>'example.txt'</span><span>)</span><span>.then</span><span>((</span><span>data</span><span>)</span><span> =></span><span>{</span><span>console.log</span><span>(</span><span>data</span><span>);</span><span>})</span><span>.catch</span><span>((</span><span>err</span><span>)</span><span> =></span><span>{</span><span>console.error</span><span>(</span><span>err</span><span>);</span><span>});</span>
- Chaining Promises:
<span><span>readFilePromise</span><span>(</span><span>'file1.txt'</span><span>)</span><span>.then</span><span>((</span><span>data1</span><span>)</span><span> =></span><span>{</span><span>console.log</span><span>(</span><span>'Data from file1:'</span><span>,</span><span> data1</span><span>);</span><span>return</span><span> readFilePromise</span><span>(</span><span>'file2.txt'</span><span>);</span><span>})</span><span>.then</span><span>((</span><span>data2</span><span>)</span><span> =></span><span>{</span><span>console.log</span><span>(</span><span>'Data from file2:'</span><span>,</span><span> data2</span><span>);</span><span>})</span><span>.catch</span><span>((</span><span>err</span><span>)</span><span> =></span><span>{</span><span>console.error</span><span>(</span><span>err</span><span>);</span><span>});</span>
4.4. Async/Await
Async/await is a more recent addition to JavaScript that simplifies asynchronous programming even further. It allows you to write asynchronous code that looks and behaves a bit more like synchronous code:
- Using Async/Await:
<span><span>const</span><span> fs </span><span>=</span><span> require</span><span>(</span><span>'fs'</span><span>);</span><span>async</span><span> function</span><span> readFileAsync</span><span>(</span><span>filePath</span><span>)</span><span>{</span><span>try</span><span>{</span><span>const</span><span> data </span><span>=</span><span> await</span><span> fs.promises.readFile</span><span>(</span><span>filePath</span><span>,</span><span> 'utf8'</span><span>);</span><span>console.log</span><span>(</span><span>data</span><span>);</span><span>}</span><span>catch</span><span> (err)</span><span>{</span><span>console.error</span><span>(</span><span>err</span><span>);</span><span>}</span><span>}</span><span>readFileAsync</span><span>(</span><span>'example.txt'</span><span>);</span>
- Benefits of Async/Await:
- Makes asynchronous code easier to read and understand.
- Reduces the complexity of handling asynchronous operations.
- Simplifies error handling with try/catch blocks.
Understanding and mastering asynchronous programming techniques is essential for building efficient and scalable Node.js applications.
5. Building Web Applications with Express.js
5.1. Introduction to Express.js
Express.js is a fast, unopinionated, minimalist web framework for Node.js. It provides a set of features for building web applications and APIs, making it easier to handle routing, middleware, and templating:
- Key Features:
- Routing: Handles HTTP requests based on the URL and HTTP method.
- Middleware: Functions that have access to the request and response objects, allowing you to perform tasks such as authentication, logging, and request modification.
- Templating: Supports various templating engines for generating dynamic HTML.
- Static Files: Serves static files such as HTML, CSS, and JavaScript.
5.2. Setting Up an Express.js Application
- Create a New Directory:
<span><span>mkdir</span><span> express-app</span></span> <span><span>cd</span><span> express-app</span></span>
- Initialize NPM:
<span><span>npm</span><span> init</span><span> -y</span></span>
- Install Express.js:
<span><span>npm</span><span> install</span><span> express</span></span>
- Create a File Named
app.js
:- Open
app.js
in your text editor and add the following code:
- Open
<span><span>const</span><span> express </span><span>=</span><span> require</span><span>(</span><span>'express'</span><span>);</span><span>const</span><span> app </span><span>=</span><span> express</span><span>();</span><span>const</span><span> port </span><span>=</span><span> 3000</span><span>;</span><span>app.get</span><span>(</span><span>'/'</span><span>,</span><span> (</span><span>req</span><span>,</span><span> res</span><span>)</span><span> =></span><span>{</span><span>res.send</span><span>(</span><span>'Hello, Express.js!'</span><span>);</span><span>});</span><span>app.listen</span><span>(</span><span>port</span><span>,</span><span> () </span><span>=></span><span>{</span><span>console.log</span><span>(</span><span>`Server running at http://localhost:${port}/`</span><span>);</span><span>});</span>
- Run the Application:
- Open your terminal, navigate to the
express-app
directory, and run:
- Open your terminal, navigate to the
<span><span>node</span><span> app.js</span></span>
- View the Output:
- Open your web browser and navigate to
http://localhost:3000
. - You should see “Hello, Express.js ” displayed in your browser.
- Open your web browser and navigate to
5.3. Routing in Express.js
Routing refers to determining how an application responds to a client request to a particular endpoint, which is a URI (Uniform Resource Identifier) and a specific HTTP request method (GET, POST, PUT, DELETE, etc.):
- Basic Routing:
<span><span>app.get</span><span>(</span><span>'/'</span><span>,</span><span> (</span><span>req</span><span>,</span><span> res</span><span>)</span><span> =></span><span>{</span><span>res.send</span><span>(</span><span>'Hello, Express.js!'</span><span>);</span><span>});</span><span>app.post</span><span>(</span><span>'/api/data'</span><span>,</span><span> (</span><span>req</span><span>,</span><span> res</span><span>)</span><span> =></span><span>{</span><span>res.json</span><span>({</span><span> message</span><span>:</span><span> 'Data received successfully'</span><span> });</span><span>});</span>
- Route Parameters:
<span><span>app.get</span><span>(</span><span>'/users/:userId'</span><span>,</span><span> (</span><span>req</span><span>,</span><span> res</span><span>)</span><span> =></span><span>{</span><span>const</span><span> userId </span><span>=</span><span> req.params.userId</span><span>;</span><span>res.send</span><span>(</span><span>`User ID: ${userId}`</span><span>);</span><span>});</span>
5.4. Middleware in Express.js
Middleware functions are functions that have access to the request object (req
), the response object (res
), and the next middleware function in the application’s request-response cycle. Middleware functions can perform the following tasks:
-
Execute any code.
-
Make changes to the request and the response objects.
-
End the request-response cycle.
-
Call the next middleware function in the stack.
-
Example:
<span><span>const</span><span> express </span><span>=</span><span> require</span><span>(</span><span>'express'</span><span>);</span><span>const</span><span> app </span><span>=</span><span> express</span><span>();</span><span>const</span><span> port </span><span>=</span><span> 3000</span><span>;</span><span>// Middleware function</span><span>const</span><span> logger </span><span>=</span><span> (</span><span>req</span><span>,</span><span> res</span><span>,</span><span> next</span><span>)</span><span> =></span><span>{</span><span>console.log</span><span>(</span><span>`Request URL: ${req.url}`</span><span>);</span><span>next</span><span>();</span><span>};</span><span>// Use the middleware</span><span>app.use</span><span>(</span><span>logger</span><span>);</span><span>app.get</span><span>(</span><span>'/'</span><span>,</span><span> (</span><span>req</span><span>,</span><span> res</span><span>)</span><span> =></span><span>{</span><span>res.send</span><span>(</span><span>'Hello, Express.js!'</span><span>);</span><span>});</span><span>app.listen</span><span>(</span><span>port</span><span>,</span><span> () </span><span>=></span><span>{</span><span>console.log</span><span>(</span><span>`Server running at http://localhost:${port}/`</span><span>);</span><span>});</span>
5.5. Serving Static Files
Express.js can serve static files such as HTML, CSS, and JavaScript from a directory:
- Create a Directory Named
public
: - Place Your Static Files in the
public
Directory: - Use the
express.static
Middleware:
<span><span>const</span><span> express </span><span>=</span><span> require</span><span>(</span><span>'express'</span><span>);</span><span>const</span><span> app </span><span>=</span><span> express</span><span>();</span><span>const</span><span> port </span><span>=</span><span> 3000</span><span>;</span><span>// Serve static files from the 'public' directory</span><span>app.use</span><span>(</span><span>express.static</span><span>(</span><span>'public'</span><span>));</span><span>app.listen</span><span>(</span><span>port</span><span>,</span><span> () </span><span>=></span><span>{</span><span>console.log</span><span>(</span><span>`Server running at http://localhost:${port}/`</span><span>);</span><span>});</span>
Now, you can access your static files by navigating to http://localhost:3000/yourfile.html
.
Express.js simplifies the process of building web applications and APIs in Node.js. By mastering routing, middleware, and static file serving, you can create robust and scalable web applications.
6. Working with Databases in Node.js
6.1. Introduction to Databases
Node.js applications often need to interact with databases to store and retrieve data. There are various types of databases you can use with Node.js, including:
- Relational Databases (SQL):
- MySQL: A popular open-source relational database management system.
- PostgreSQL: An advanced open-source relational database system known for its reliability and features.
- NoSQL Databases:
- MongoDB: A popular NoSQL database that stores data in flexible, JSON-like documents.
- Redis: An in-memory data structure store, often used as a cache or message broker.
6.2. Connecting to MongoDB with Mongoose
Mongoose is an Object Data Modeling (ODM) library for MongoDB and Node.js. It provides a higher-level abstraction for interacting with MongoDB, making it easier to define schemas, validate data, and perform queries:
- Install Mongoose:
<span><span>npm</span><span> install</span><span> mongoose</span></span>
- Connect to MongoDB:
<span><span>const</span><span> mongoose </span><span>=</span><span> require</span><span>(</span><span>'mongoose'</span><span>);</span><span>mongoose.connect</span><span>(</span><span>'mongodb://localhost:27017/mydatabase'</span><span>,</span><span>{</span><span>useNewUrlParser</span><span>:</span><span> true</span><span>,</span><span>useUnifiedTopology</span><span>:</span><span> true</span><span>})</span><span>.then</span><span>(()</span><span>=></span><span>console.log</span><span>(</span><span>'Connected to MongoDB'</span><span>))</span><span>.catch</span><span>((</span><span>err</span><span>)</span><span>=></span><span>console.error</span><span>(</span><span>'MongoDB connection error:'</span><span>,</span><span> err</span><span>));</span>
- Define a Schema:
<span><span>const</span><span> Schema </span><span>=</span><span> mongoose.Schema</span><span>;</span><span>const</span><span> userSchema </span><span>=</span><span> new</span><span> Schema</span><span>({</span><span>name</span><span>:</span><span> String</span><span>,</span><span>email</span><span>:</span><span> String</span><span>,</span><span>age</span><span>:</span><span> Number</span><span>});</span><span>const</span><span> User </span><span>=</span><span> mongoose.model</span><span>(</span><span>'User'</span><span>,</span><span> userSchema</span><span>);</span>
- Create a Document:
<span><span>const</span><span> newUser </span><span>=</span><span> new</span><span> User</span><span>({</span><span>name</span><span>:</span><span> 'John Doe'</span><span>,</span><span>email</span><span>:</span><span> 'john.doe@example.com'</span><span>,</span><span>age</span><span>:</span><span> 30</span><span>});</span><span>newUser.save</span><span>()</span><span>.then</span><span>(()</span><span>=></span><span>console.log</span><span>(</span><span>'User saved successfully'</span><span>))</span><span>.catch</span><span>((</span><span>err</span><span>)</span><span>=></span><span>console.error</span><span>(</span><span>'Error saving user:'</span><span>,</span><span> err</span><span>));</span>
- Query Documents:
<span><span>User.find</span><span>({})</span><span>.then</span><span>((</span><span>users</span><span>)</span><span>=></span><span>console.log</span><span>(</span><span>'Users:'</span><span>,</span><span> users</span><span>))</span><span>.catch</span><span>((</span><span>err</span><span>)</span><span>=></span><span>console.error</span><span>(</span><span>'Error fetching users:'</span><span>,</span><span> err</span><span>));</span>
6.3. Connecting to PostgreSQL with Sequelize
Sequelize is a promise-based Node.js ORM (Object-Relational Mapping) for PostgreSQL, MySQL, SQLite, and MariaDB. It provides a set of tools for defining models, performing queries, and managing database schemas:
- Install Sequelize and the PostgreSQL Driver:
<span><span>npm</span><span> install</span><span> sequelize pg pg-hstore</span></span>
- Configure Sequelize:
<span><span>const</span><span> Sequelize </span><span>=</span><span> require</span><span>(</span><span>'sequelize'</span><span>);</span><span>const</span><span> sequelize </span><span>=</span><span> new</span><span> Sequelize</span><span>(</span><span>'mydatabase'</span><span>,</span><span> 'username'</span><span>,</span><span> 'password'</span><span>,</span><span>{</span><span>host</span><span>:</span><span> 'localhost'</span><span>,</span><span>dialect</span><span>:</span><span> 'postgres'</span><span>});</span><span>sequelize.authenticate</span><span>()</span><span>.then</span><span>(()</span><span>=></span><span>console.log</span><span>(</span><span>'Connected to PostgreSQL'</span><span>))</span><span>.catch</span><span>((</span><span>err</span><span>)</span><span>=></span><span>console.error</span><span>(</span><span>'Unable to connect to the database:'</span><span>,</span><span> err</span><span>));</span>
- Define a Model:
<span><span>const</span><span> User </span><span>=</span><span> sequelize.define</span><span>(</span><span>'user'</span><span>,</span><span>{</span><span>name</span><span>:</span><span>{</span><span>type</span><span>:</span><span> Sequelize.STRING</span><span>,</span><span>allowNull</span><span>:</span><span> false</span><span>},</span><span>email</span><span>:</span><span>{</span><span>type</span><span>:</span><span> Sequelize.STRING</span><span>,</span><span>unique</span><span>:</span><span> true</span><span>},</span><span>age</span><span>:</span><span>{</span><span>type</span><span>:</span><span> Sequelize.INTEGER</span><span>}</span><span>});</span><span>sequelize.sync</span><span>()</span><span>.then</span><span>(()</span><span>=></span><span>console.log</span><span>(</span><span>'Database synced'</span><span>));</span>
- Create a Record:
<span><span>User.create</span><span>({</span><span>name</span><span>:</span><span> 'Jane Doe'</span><span>,</span><span>email</span><span>:</span><span> 'jane.doe@example.com'</span><span>,</span><span>age</span><span>