JavaScript was originally designed for client - side scripting in web browsers. However, Node.js brings JavaScript to the server - side. Node.js uses the V8 JavaScript engine, the same engine that powers Google Chrome, to execute JavaScript code outside of the browser.
Node.js is built on an event - driven, non - blocking I/O model. This means that instead of waiting for an I/O operation (like reading a file or making a database query) to complete, Node.js can continue executing other tasks. It uses an event loop to handle asynchronous operations efficiently. For example, when a client makes a request to a Node.js server, the server can handle multiple requests simultaneously without blocking the execution thread.
Node.js runs in a single thread, which might seem limiting. But thanks to its asynchronous nature, it can handle multiple concurrent requests. The event loop continuously checks for completed asynchronous operations and executes the corresponding callbacks. For instance, if a server has to read a large file, it can start the read operation and continue serving other requests while waiting for the read to finish.
Node.js uses a module system to organize code. A module is a self - contained piece of code that can be reused across different parts of an application. There are three types of modules in Node.js:
http
, fs
(file system), and path
. For example, the http
module is used to create HTTP servers and clients.const http = require('http');
const server = http.createServer((req, res) => {
res.end('Hello, World!');
});
server.listen(3000, () => {
console.log('Server is running on port 3000');
});
greet.js
with the following content:// greet.js
module.exports = function() {
return 'Hello!';
};
You can use it in another file like this:
const greet = require('./greet');
console.log(greet());
express
is a popular third - party module for building web applications.To set up a basic HTTP server in Node.js using the built - in http
module, you can follow these steps:
// Import the http module
const http = require('http');
// Create an HTTP server
const server = http.createServer((request, response) => {
// Set the response HTTP header with HTTP status and Content type
response.writeHead(200, {'Content-Type': 'text/plain'});
// Send the response body "Hello, World!"
response.end('Hello, World!\n');
});
// Listen on port 3000, IP defaults to 127.0.0.1
server.listen(3000, () => {
console.log('Server running at http://127.0.0.1:3000/');
});
In this code:
http
module, which is a core module in Node.js for creating HTTP servers and clients.createServer
method. The callback function passed to createServer
takes two parameters: request
(an object representing the incoming HTTP request) and response
(an object for sending the HTTP response).In a real - world server - side application, you often need to handle different routes. For simplicity, let’s extend the previous example to handle different routes using the http
module:
const http = require('http');
const server = http.createServer((req, res) => {
if (req.url === '/') {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Welcome to the home page!');
} else if (req.url === '/about') {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('This is the about page.');
} else {
res.writeHead(404, {'Content-Type': 'text/plain'});
res.end('404 Not Found');
}
});
server.listen(3000, () => {
console.log('Server running at http://127.0.0.1:3000/');
});
In this code, we check the req.url
property to determine which route the client is requesting and send an appropriate response.
Node.js is designed to handle asynchronous operations efficiently. For example, reading a file asynchronously using the fs
module:
const fs = require('fs');
fs.readFile('example.txt', 'utf8', (err, data) => {
if (err) {
console.error(err);
return;
}
console.log(data);
});
console.log('This will be printed first because readFile is asynchronous');
In this code, the readFile
function is an asynchronous operation. The callback function is executed once the file reading is complete. Meanwhile, the code after the readFile
call continues to execute, which is why the console log statement after readFile
is printed first.
Express.js is a minimalist web application framework for Node.js. It simplifies the process of building web applications and APIs.
First, initialize a new Node.js project and install Express:
mkdir my - express - app
cd my - express - app
npm init -y
npm install express
const express = require('express');
const app = express();
// Define a route
app.get('/', (req, res) => {
res.send('Hello from Express!');
});
// Start the server
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
In this code:
express
module and create an Express application instance.get
method. When a client makes a GET request to the root path (/
), the server sends the response “Hello from Express!”.Most server - side applications need to interact with databases. For example, using the mysql
package to connect to a MySQL database:
const mysql = require('mysql');
// Create a connection
const connection = mysql.createConnection({
host: 'localhost',
user: 'your_username',
password: 'your_password',
database: 'your_database'
});
// Connect to the database
connection.connect((err) => {
if (err) {
console.error('Error connecting to database: ', err);
return;
}
console.log('Connected to the database');
// Query the database
const query = 'SELECT * FROM users';
connection.query(query, (err, results) => {
if (err) {
console.error('Error executing query: ', err);
return;
}
console.log(results);
});
// Close the connection
connection.end();
});
Proper error handling is crucial in server - side applications. In an Express application, you can use middleware to handle errors:
const express = require('express');
const app = express();
// Middleware for handling requests
app.get('/', (req, res, next) => {
try {
// Simulate an error
throw new Error('Something went wrong');
} catch (err) {
next(err);
}
});
// Error - handling middleware
app.use((err, req, res, next) => {
console.error(err);
res.status(500).send('Internal Server Error');
});
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
express - validator
package to validate user input.const express = require('express');
const { body, validationResult } = require('express-validator');
const app = express();
app.use(express.json());
app.post('/user', [
body('email').isEmail().withMessage('Invalid email'),
body('password').isLength({ min: 6 }).withMessage('Password must be at least 6 characters long')
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Proceed with user creation
res.send('User created successfully');
});
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
https
module in Node.js or a reverse proxy like Nginx to set up HTTPS.node - cache
can be used to store frequently accessed data.async/await
to ensure that the application can handle multiple requests efficiently without blocking the event loop.Building server - side applications with Node.js and JavaScript offers numerous advantages, such as using a single language across the full - stack, efficient handling of concurrent requests, and a vast ecosystem of modules. By understanding the fundamental concepts, following common practices, and adhering to best practices, developers can create robust, scalable, and secure server - side applications. Whether it’s a simple web application or a complex enterprise - level API, Node.js and JavaScript provide the tools and flexibility needed for modern server - side development.