Node.js Core Concepts and Web Development Essentials

Node.js Runtime Basics

Node.js executes JavaScript outside the browser, meaning browser-specific APIs like window or document are unavailable. Verify the installation using node -v and execute scripts via node app.js.

console.log('Executing within Node runtime');
console.log(window); // Throws ReferenceError
console.log(document); // Throws ReferenceError

Binary Data Handling with Buffer

Buffer instances represent fixed-size chunks of raw binary data allocated in memory. They operate similarly to arrays of integers but correspond directly to raw memory allocations, where each element consumes exactly one byte.

Buffer Instantiation

Creation methods include allocating zero-filled memory, allocating uninitialized memory, and converting existing data structures.

// Allocates 8 bytes initialized to zero
const safeBuffer = Buffer.alloc(8); // <Buffer 00 00 00 00 00 00 00 00>

// Allocates 8 bytes without initialization (potentially contains old data)
const fastBuffer = Buffer.allocUnsafe(8);

// Creates buffer from a string
const textBuffer = Buffer.from('nodejs');

// Creates buffer from an array of byte values
const arrayBuffer = Buffer.from([110, 111, 100, 101]);

Data Conversion and Access

Use toString() (defaults to UTF-8) to decode buffers. Individual bytes can be accessed or modified using index notation. Overflows beyond 255 are truncated to the lower 8 bits. A single UTF-8 Chinese character typically occupies 3 bytes.

console.log(arrayBuffer.toString()); // "node"
console.log(textBuffer[0]); // 110 (ASCII for 'n')
textBuffer[0] = 109; // Modifies first byte
console.log(textBuffer.toString()); // "modejs"

File System Operations

The fs module enables interaction with the operating system's file system. Operations are categorized into synchronous, asynchronous callback, and streaming methodologies.

Writing Data

MethodDescription
writeFileAsynchronous file write
writeFileSyncSynchronous file write
appendFileAsynchronous append to file
createWriteStreamStreaming data write
const fileSystem = require('fs');

// Asynchronous write
fileSystem.writeFile('./docs/note.txt', 'Initial content', (writeErr) => {
    if (writeErr) throw writeErr;
    console.log('Write operation completed');
});

// Synchronous write
fileSystem.writeFileSync('./logs/sys.txt', 'Log entry');

// Appending data
fileSystem.appendFileSync('./docs/note.txt', '\nAppended text');

// Streaming write (ideal for large or continuous data)
const streamWriter = fileSystem.createWriteStream('./media/video.mp4');
streamWriter.write('Chunk 1');
streamWriter.write('Chunk 2');
streamWriter.end();

Synchronous methods block the main thread until the I/O completes, whereas asynchronous methods delegate operations to background threads, executing a callback upon completion. Streaming minimizes file open/close overhead, optimizing frequent write scenarios.

Reading Data

const fileSystem = require('fs');

// Asynchronous read (returns Buffer unless encoding specified)
fileSystem.readFile('./docs/note.txt', 'utf8', (readErr, fileData) => {
    if (readErr) throw readErr;
    console.log(fileData);
});

// Synchronous read
const rawContent = fileSystem.readFileSync('./docs/note.txt');
console.log(rawContent.toString('utf8'));

// Streaming read (processes data in chunks)
const streamReader = fileSystem.createReadStream('./media/video.mp4', 'utf8');
streamReader.on('data', (chunk) => {
    console.log(`Received ${chunk.length} bytes`);
});
streamReader.on('end', () => {
    console.log('Stream finished');
});

File Management

Renaming, moving, and deleting files utilize rename/unlink and their synchronous counterparts.

fileSystem.rename('./docs/note.txt', './archive/old_note.txt', (err) => {
    if (err) throw err;
});

fileSystem.unlink('./archive/old_note.txt', (err) => {
    if (err) throw err;
});

Directory Management

// Creating directories (recursive option builds nested paths)
fileSystem.mkdir('./storage/data', { recursive: true }, (err) => {
    if (err) throw err;
});

// Reading directory contents
fileSystem.readdir('./storage', (err, files) => {
    if (err) throw err;
    console.log(files);
});

// Removing directories (recursive removes nested content)
fileSystem.rmdir('./storage', { recursive: true }, (err) => {
    if (err) throw err;
});

Path Resolution and Metadata

Relative paths reference the command line's working directory, not the script's location. The global __dirname variable provides the absolute path of the current script directory, ensuring reliable file references.

const stats = fileSystem.statSync('./docs/note.txt');
console.log(stats.isFile()); // true
console.log(stats.isDirectory()); // false

Path Manipulations

The path module standardizes path operations across different operating systems.

const pathModule = require('path');

const fullPath = 'C:\projects\web\src\app.js';

console.log(pathModule.sep); // '\' on Windows, '/' on POSIX
console.log(pathModule.resolve(__dirname, 'config.json')); // Absolute path
console.log(pathModule.parse(fullPath)); // { root, dir, base, ext, name }
console.log(pathModule.basename(fullPath)); // 'app.js'
console.log(pathModule.dirname(fullPath)); // 'C:\projects\web\src'
console.log(pathModule.extname(fullPath)); // '.js'

Building HTTP Servers

The http module allows creation of raw web servers. The server processes incoming requests and constructs responses.

const httpModule = require('http');

const webServer = httpModule.createServer((clientReq, serverRes) => {
    serverRes.setHeader('Content-Type', 'text/html; charset=utf-8');
    serverRes.end('<h1>Server Active</h1>');
});

webServer.listen(8080, () => {
    console.log('Server running on port 8080');
});

The clientReq object contains request details (method, URL, headers). request.url only yields the path and query string. The serverRes object sends data back to the client, and response.end() must be called to finalize every request.

Serving Static Assets

Static assets (images, stylesheets) remain unchanged over time. The server can read files based on the request URL and stream them back. Setting the correct Content-Type (MIME type) is essential; unknown types default to application/octet-stream, prompting a file download.

const fileSystem = require('fs');
const httpModule = require('http');

const staticServer = httpModule.createServer((req, res) => {
    const targetPath = pathModule.join(__dirname, 'public', req.url);
    
    fileSystem.readFile(targetPath, (err, data) => {
        if (err) {
            res.statusCode = 404;
            res.end('Resource not found');
            return;
        }
        res.end(data);
    });
});
staticServer.listen(8080);

Module Systems

Modularization divides complex applications into isolated files, preventing naming conflicts and enhancing reusability.

CommonJS

Node.js natively implements CommonJS, utilizing require() for importing and module.exports or exports for exporting. Exports ultimately reference module.exports; reassigning exports directly breaks the binding.

// utils.js
function calculateSum(a, b) { return a + b; }
module.exports = { calculateSum };

// main.js
const utilities = require('./utils');
console.log(utilities.calculateSum(2, 5));

Custom modules require relative paths (prefixed with ./ or ../). Module resolution checks node_modules, package.json main field, and index.js fallbacks.

ES Modules

ES Modules employ static import/export syntax, enabling tree-shaking optimizations. Node.js requires "type": "module" in package.json or .mjs extensions. Browser environments use <script type="module">.

// math.mjs
export default function multiply(x, y) { return x * y; }
export function subtract(x, y) { return x - y; }

// app.mjs
import multiply, { subtract } from './math.mjs';
console.log(multiply(4, 3));
console.log(subtract(10, 6));

Package Management

Node Package Manager (npm) handles dependency lifecycle. Initializing a project generates a package.json manifest.

npm init -y
npm install express --save
npm install eslint --save-dev
npm uninstall eslint

Dependencies essential for runtime belong in dependencies, while build-time tools reside in devDependencies. Global installations (-g) register CLI tools like nodemon.

Mirror Configuration

Using the nrm registry manager accelerates downloads.

npm install -g nrm
nrm use taobao

Yarn

Yarn offers deterministic installations via lockfiles and parallel downloading.

yarn init
yarn add express
yarn add eslint --dev
yarn remove eslint

Managing Node Versions

Node Version Manager (nvm) allows switching between multiple Node.js runtime versions.

nvm install 18.0.0
nvm use 18.0.0
nvm list

Express Framework

Express abstracts the raw http module, providing robust routing, middleware support, and simplified response handling.

const expressApp = require('express');
const app = expressApp();

app.get('/api/status', (req, res) => {
    res.send({ status: 'Operational' });
});

app.listen(3000);

Routing and Parameters

Routes map HTTP methods and paths to handler functions. Query strings populate req.query, while dynamic URL segments map to req.params.

app.get('/users/:userId', (req, res) => {
    res.send(`Fetching user ${req.params.userId}`);
});

Middleware Architecture

Middleware functions intercept requests, executing logic before passing control via next(). Global middleware binds via app.use(), while route-specific middleware applies to individual endpoints.

const authCheck = (req, res, next) => {
    if (!req.headers.authorization) return res.status(401).send('Unauthorized');
    next();
};

app.use(expressApp.static('assets')); // Static middleware
app.use(expressApp.urlencoded({ extended: false })); // Body parsing middleware
app.get('/admin', authCheck, (req, res) => res.send('Admin Panel'));

Router Modularity

The express.Router() class creates modular, mountable route handlers.

// userRoutes.js
const router = expressApp.Router();
router.get('/', (req, res) => res.send('User List'));
module.exports = router;

// app.js
const userRoutes = require('./userRoutes');
app.use('/users', userRoutes);

EJS Templating

Embedding JavaScript into HTML via EJS (<%= variable %>) enables dynamic server-side rendering.

app.set('view engine', 'ejs');
app.get('/dashboard', (req, res) => {
    res.render('dashboard', { user: 'Admin' });
});

MongoDB and Mongoose

MongoDB stores data as BSON documents within collections. The Mongoose ODM bridges Node.js and MongoDB, enforcing schema validation.

Database Connection

const mongooseODM = require('mongoose');
mongooseODM.connect('mongodb://localhost:27017/appdb');

const itemSchema = new mongooseODM.Schema({
    title: { type: String, required: true, unique: true },
    category: { type: String, enum: ['tech', 'sports', 'art'] },
    price: { type: Number, default: 0 }
});

const ItemModel = mongooseODM.model('Item', itemSchema);

CRUD Operations

// Create
ItemModel.create({ title: 'Laptop', category: 'tech', price: 999 });

// Read
ItemModel.find({ category: 'tech' });
ItemModel.findById('abc123');

// Update
ItemModel.updateOne({ title: 'Laptop' }, { price: 899 });
ItemModel.findByIdAndUpdate('abc123', { price: 799 });

// Delete
ItemModel.deleteOne({ title: 'Laptop' });

Query Conditions

Comparison operators ($gt, $lt, $gte, $lte, $ne) and logical operators ($or, $and) filter data. Regular expressions enable fuzzy searches.

ItemModel.find({ price: { $gte: 100, $lte: 500 } });
ItemModel.find({ $or: [{ category: 'tech' }, { category: 'art' }] });
ItemModel.find({ title: /^Lap/ });

Projections exclude/include fields, sorting orders results, and skip/limit implements pagination.

ItemModel.find().select({ title: 1, _id: 0 }).sort({ price: -1 }).skip(10).limit(5);

API Design

RESTful APIs map HTTP verbs (GET, POST, PUT, DELETE) to CRUD operations on resource-based URLs, avoiding verbs in endpoints. json-server rapidly prototypes REST backends from JSON files.

npm install -g json-server
json-server --watch mock_db.json

State Management

HTTP lacks inherent state. Mechanisms like Cookies, Sessions, and Tokens persist user context.

Cookies

Cookies store small data strings client-side, transmitted automatically with matching domain requests.

res.cookie('sessionId', 'xyz789', { maxAge: 3600000, httpOnly: true });
res.clearCookie('sessionId');

Sessions

Sessions reside server-side, mapping a client cookie (containing an ID) to stored data.

const sessionMiddleware = require('express-session');
app.use(sessionMiddleware({
    secret: 'encryption_key',
    resave: false,
    saveUninitialized: true,
    cookie: { secure: false }
}));

req.session.userRole = 'admin';

Tokens (JWT)

JSON Web Tokens encode user claims within a cryptographically signed string, residing entirely client-side, ideal for mobile applications and cross-service authentication.

const jwtLib = require('jsonwebtoken');
const generatedToken = jwtLib.sign({ userId: 123 }, 'secret_key', { expiresIn: '1h' });
jwtLib.verify(generatedToken, 'secret_key');

Console Inspection

To output deeply nested object structures completely, specify infinite depth.

console.dir(complexObject, { depth: null, colors: true });

Tags: Node.js Express mongodb javascript Backend

Posted on Tue, 18 Aug 2026 16:26:55 +0000 by killswitchfilter