Dev Logs
/Node.js & Express/ Node.js Core Modules: Built-in Functionality
Chapters
  • 01Node.js Fundamentals: Understanding the Runtime
  • 02Node.js Installation and Running Basic Scripts
  • 03NPM: Node Package Manager Fundamentals
  • 04Node.js Core Modules: Built-in Functionality
    • Overview
    • Key Concepts
    • What are Core Modules?
    • CommonJS vs ES Modules
    • Synchronous vs Asynchronous APIs
    • Example Code
    • File System (fs) Module
    • Path Module
    • HTTP Module
    • OS Module
    • URL Module
    • Real-World Use Case
    • File-based Logger with Core Modules
    • Best Practices
    • . Always Use Asynchronous APIs
    • . Handle Errors Properly
    • . Use Path Module for Cross-Platform Compatibility
    • . Validate Input and Handle Edge Cases
    • . Use Streams for Large Files
    • Summary
  • 05Creating HTTP Servers with Node.js
  • 06Introduction to Express.js: Web Framework for Node.js
  • 07Handling Request and Response Objects in Express.js
  • 08Serving Static Files in Express.js
  • 09Environment Variables with dotenv
  • 10Express Router and Modular Route Management
  • 11Template Engines: EJS and Pug for Server-Side Rendering
  • 12RESTful API Design Principles
  • 13CRUD Operations with Express.js
  • 14Middleware in Express.js
  • 15Database Integration: MongoDB and Mongoose
  • 16Authentication and Authorization in Express.js
All chapters

Node.js Core Modules: Built-in Functionality

Overview

Node.js comes with a rich set of built-in modules that provide essential functionality without requiring external dependencies. These core modules handle file system operations, HTTP requests, path manipulation, operating system interactions, and much more. Understanding these modules is crucial for effective Node.js development.

Key Concepts

What are Core Modules?

Core modules are built into Node.js and can be imported using require() without installation. They provide:

  • File system operations
  • HTTP/HTTPS functionality
  • Path and URL utilities
  • Operating system information
  • Cryptographic functions
  • Stream processing
  • And much more

CommonJS vs ES Modules

javascript
// CommonJS (traditional)
const fs = require("fs");

// ES Modules (modern)
import fs from "fs";
import { readFile } from "fs";

Synchronous vs Asynchronous APIs

Most core modules provide both sync and async versions:

  • Async: Non-blocking, callback-based or Promise-based
  • Sync: Blocking, returns result directly

Example Code

File System (fs) Module

javascript
// fs-examples.js
const fs = require("fs");
const path = require("path");

// Reading files
// Asynchronous (preferred)
fs.readFile("data.txt", "utf8", (err, data) => {
  if (err) {
    console.error("Error reading file:", err.message);
    return;
  }
  console.log("File content:", data);
});

// Promise-based (modern approach)
const fsPromises = require("fs").promises;

async function readFileAsync() {
  try {
    const data = await fsPromises.readFile("data.txt", "utf8");
    console.log("File content (async/await):", data);
  } catch (error) {
    console.error("Error:", error.message);
  }
}

// Synchronous (use sparingly)
try {
  const data = fs.readFileSync("data.txt", "utf8");
  console.log("File content (sync):", data);
} catch (error) {
  console.error("Error:", error.message);
}

// Writing files
const content = "Hello, Node.js!\nThis is a test file.";

// Asynchronous write
fs.writeFile("output.txt", content, "utf8", (err) => {
  if (err) {
    console.error("Error writing file:", err);
    return;
  }
  console.log("File written successfully!");
});

// Promise-based write
async function writeFileAsync() {
  try {
    await fsPromises.writeFile("output-async.txt", content, "utf8");
    console.log("File written successfully (async/await)!");
  } catch (error) {
    console.error("Error writing file:", error.message);
  }
}

// Appending to files
fs.appendFile("log.txt", `\n${new Date().toISOString()} - Log entry`, (err) => {
  if (err) {
    console.error("Error appending to file:", err);
    return;
  }
  console.log("Log entry added!");
});

// Working with directories
fs.readdir(".", (err, files) => {
  if (err) {
    console.error("Error reading directory:", err);
    return;
  }
  console.log("Files in current directory:", files);
});

// Creating directories
fs.mkdir("new-folder", { recursive: true }, (err) => {
  if (err) {
    console.error("Error creating directory:", err);
    return;
  }
  console.log("Directory created!");
});

// File stats
fs.stat("package.json", (err, stats) => {
  if (err) {
    console.error("Error getting file stats:", err);
    return;
  }

  console.log("File stats:");
  console.log("  Size:", stats.size, "bytes");
  console.log("  Is file:", stats.isFile());
  console.log("  Is directory:", stats.isDirectory());
  console.log("  Created:", stats.birthtime);
  console.log("  Modified:", stats.mtime);
});

// Check if file exists
fs.access("somefile.txt", fs.constants.F_OK, (err) => {
  if (err) {
    console.log("File does not exist");
  } else {
    console.log("File exists");
  }
});

Path Module

javascript
// path-examples.js
const path = require("path");

// Path manipulation
const filePath = "/users/john/documents/file.txt";

console.log("Full path:", filePath);
console.log("Directory:", path.dirname(filePath)); // /users/john/documents
console.log("Filename:", path.basename(filePath)); // file.txt
console.log("Extension:", path.extname(filePath)); // .txt
console.log("Name without ext:", path.basename(filePath, ".txt")); // file

// Parsing paths
const parsed = path.parse(filePath);
console.log("Parsed path:", parsed);
// {
//   root: '/',
//   dir: '/users/john/documents',
//   base: 'file.txt',
//   ext: '.txt',
//   name: 'file'
// }

// Building paths
const newPath = path.format({
  dir: "/users/jane/projects",
  name: "app",
  ext: ".js",
});
console.log("Formatted path:", newPath); // /users/jane/projects/app.js

// Joining paths (cross-platform)
const joinedPath = path.join("/users", "john", "documents", "file.txt");
console.log("Joined path:", joinedPath);

// Resolving absolute paths
const absolutePath = path.resolve("documents", "file.txt");
console.log("Absolute path:", absolutePath);

// Relative paths
const relativePath = path.relative(
  "/users/john",
  "/users/john/documents/file.txt"
);
console.log("Relative path:", relativePath); // documents/file.txt

// Cross-platform path separators
console.log("Path separator:", path.sep); // \ on Windows, / on Unix
console.log("Path delimiter:", path.delimiter); // ; on Windows, : on Unix

// Normalize paths
const messyPath = "/users/john/../jane/./documents//file.txt";
console.log("Normalized:", path.normalize(messyPath)); // /users/jane/documents/file.txt

HTTP Module

javascript
// http-examples.js
const http = require("http");
const url = require("url");
const querystring = require("querystring");

// Basic HTTP server
const server = http.createServer((req, res) => {
  // Parse URL
  const parsedUrl = url.parse(req.url, true);
  const pathname = parsedUrl.pathname;
  const query = parsedUrl.query;

  // Set CORS headers
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
  res.setHeader("Access-Control-Allow-Headers", "Content-Type");

  // Handle different routes
  if (pathname === "/") {
    res.writeHead(200, { "Content-Type": "text/html" });
    res.end(`
            <h1>Welcome to Node.js HTTP Server</h1>
            <p>Current time: ${new Date().toISOString()}</p>
            <ul>
                <li><a href="/api/users">Users API</a></li>
                <li><a href="/api/health">Health Check</a></li>
                <li><a href="/api/info?name=John&age=30">Info with Query</a></li>
            </ul>
        `);
  } else if (pathname === "/api/users") {
    const users = [
      { id: 1, name: "John Doe", email: "john@example.com" },
      { id: 2, name: "Jane Smith", email: "jane@example.com" },
    ];

    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify(users, null, 2));
  } else if (pathname === "/api/health") {
    const healthData = {
      status: "OK",
      timestamp: new Date().toISOString(),
      uptime: process.uptime(),
      memory: process.memoryUsage(),
    };

    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify(healthData, null, 2));
  } else if (pathname === "/api/info") {
    const info = {
      message: "Hello from Node.js!",
      query: query,
      method: req.method,
      headers: req.headers,
      url: req.url,
    };

    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify(info, null, 2));
  } else if (req.method === "POST" && pathname === "/api/data") {
    let body = "";

    req.on("data", (chunk) => {
      body += chunk.toString();
    });

    req.on("end", () => {
      try {
        const data = JSON.parse(body);
        const response = {
          message: "Data received successfully",
          receivedData: data,
          timestamp: new Date().toISOString(),
        };

        res.writeHead(200, { "Content-Type": "application/json" });
        res.end(JSON.stringify(response, null, 2));
      } catch (error) {
        res.writeHead(400, { "Content-Type": "application/json" });
        res.end(JSON.stringify({ error: "Invalid JSON" }));
      }
    });
  } else {
    res.writeHead(404, { "Content-Type": "application/json" });
    res.end(JSON.stringify({ error: "Not Found" }));
  }
});

const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
  console.log(`🚀 Server running on http://localhost:${PORT}`);
});

// HTTP client example
function makeHttpRequest() {
  const options = {
    hostname: "jsonplaceholder.typicode.com",
    port: 443,
    path: "/posts/1",
    method: "GET",
    headers: {
      "User-Agent": "Node.js HTTP Client",
    },
  };

  const req = http.request(options, (res) => {
    let data = "";

    res.on("data", (chunk) => {
      data += chunk;
    });

    res.on("end", () => {
      console.log("Response:", JSON.parse(data));
    });
  });

  req.on("error", (error) => {
    console.error("Request error:", error);
  });

  req.end();
}

// Uncomment to test HTTP client
// makeHttpRequest();

OS Module

javascript
// os-examples.js
const os = require("os");

// System information
console.log("Operating System Information:");
console.log("Platform:", os.platform()); // win32, darwin, linux
console.log("Architecture:", os.arch()); // x64, arm64, etc.
console.log("CPU Model:", os.cpus()[0].model);
console.log("CPU Cores:", os.cpus().length);
console.log(
  "Total Memory:",
  (os.totalmem() / 1024 / 1024 / 1024).toFixed(2),
  "GB"
);
console.log(
  "Free Memory:",
  (os.freemem() / 1024 / 1024 / 1024).toFixed(2),
  "GB"
);
console.log("Uptime:", (os.uptime() / 3600).toFixed(2), "hours");
console.log("Hostname:", os.hostname());
console.log("Home Directory:", os.homedir());
console.log("Temp Directory:", os.tmpdir());
console.log("Username:", os.userInfo().username);

// Network interfaces
console.log("\nNetwork Interfaces:");
const networkInterfaces = os.networkInterfaces();
Object.keys(networkInterfaces).forEach((interfaceName) => {
  const interfaces = networkInterfaces[interfaceName];
  interfaces.forEach((interface) => {
    if (interface.family === "IPv4" && !interface.internal) {
      console.log(`${interfaceName}: ${interface.address}`);
    }
  });
});

// Load average (Unix-like systems)
if (os.platform() !== "win32") {
  console.log("\nLoad Average:", os.loadavg());
}

// EOL (End of Line) character
console.log("\nEOL character code:", os.EOL.charCodeAt(0));

URL Module

javascript
// url-examples.js
const url = require("url");
const { URL, URLSearchParams } = require("url");

// Legacy URL parsing
const urlString =
  "https://example.com:8080/path/to/resource?name=john&age=30#section1";
const parsedUrl = url.parse(urlString, true);

console.log("Legacy URL parsing:");
console.log("Protocol:", parsedUrl.protocol); // https:
console.log("Host:", parsedUrl.host); // example.com:8080
console.log("Hostname:", parsedUrl.hostname); // example.com
console.log("Port:", parsedUrl.port); // 8080
console.log("Pathname:", parsedUrl.pathname); // /path/to/resource
console.log("Query:", parsedUrl.query); // { name: 'john', age: '30' }
console.log("Hash:", parsedUrl.hash); // #section1

// Modern URL API
const modernUrl = new URL(urlString);

console.log("\nModern URL API:");
console.log("Origin:", modernUrl.origin); // https://example.com:8080
console.log("Protocol:", modernUrl.protocol); // https:
console.log("Host:", modernUrl.host); // example.com:8080
console.log("Hostname:", modernUrl.hostname); // example.com
console.log("Port:", modernUrl.port); // 8080
console.log("Pathname:", modernUrl.pathname); // /path/to/resource
console.log("Search:", modernUrl.search); // ?name=john&age=30
console.log("Hash:", modernUrl.hash); // #section1

// Working with search parameters
const params = new URLSearchParams(modernUrl.search);
console.log("\nSearch Parameters:");
console.log("Name:", params.get("name")); // john
console.log("Age:", params.get("age")); // 30

// Adding/modifying parameters
params.set("city", "New York");
params.append("hobby", "reading");
params.append("hobby", "coding");

console.log("Modified search:", params.toString());

// Building URLs
const baseUrl = "https://api.example.com";
const endpoint = "/users";
const queryParams = new URLSearchParams({
  page: "1",
  limit: "10",
  sort: "name",
});

const apiUrl = new URL(endpoint, baseUrl);
apiUrl.search = queryParams.toString();

console.log("\nBuilt API URL:", apiUrl.toString());

Real-World Use Case

File-based Logger with Core Modules

javascript
// logger.js
const fs = require("fs");
const path = require("path");
const os = require("os");

class FileLogger {
  constructor(logDir = "logs") {
    this.logDir = logDir;
    this.ensureLogDirectory();
  }

  ensureLogDirectory() {
    if (!fs.existsSync(this.logDir)) {
      fs.mkdirSync(this.logDir, { recursive: true });
    }
  }

  getLogFileName() {
    const date = new Date().toISOString().split("T")[0];
    return path.join(this.logDir, `app-${date}.log`);
  }

  formatLogEntry(level, message, meta = {}) {
    const timestamp = new Date().toISOString();
    const hostname = os.hostname();
    const pid = process.pid;

    const logEntry = {
      timestamp,
      level: level.toUpperCase(),
      message,
      hostname,
      pid,
      ...meta,
    };

    return JSON.stringify(logEntry) + os.EOL;
  }

  async writeLog(level, message, meta = {}) {
    const logEntry = this.formatLogEntry(level, message, meta);
    const logFile = this.getLogFileName();

    try {
      await fs.promises.appendFile(logFile, logEntry, "utf8");
    } catch (error) {
      console.error("Failed to write log:", error.message);
    }
  }

  info(message, meta = {}) {
    return this.writeLog("info", message, meta);
  }

  error(message, meta = {}) {
    return this.writeLog("error", message, meta);
  }

  warn(message, meta = {}) {
    return this.writeLog("warn", message, meta);
  }

  debug(message, meta = {}) {
    return this.writeLog("debug", message, meta);
  }

  async getLogs(date = null) {
    const targetDate = date || new Date().toISOString().split("T")[0];
    const logFile = path.join(this.logDir, `app-${targetDate}.log`);

    try {
      const content = await fs.promises.readFile(logFile, "utf8");
      return content
        .split(os.EOL)
        .filter((line) => line.trim())
        .map((line) => JSON.parse(line));
    } catch (error) {
      if (error.code === "ENOENT") {
        return [];
      }
      throw error;
    }
  }

  async getLogStats() {
    try {
      const files = await fs.promises.readdir(this.logDir);
      const logFiles = files.filter((file) => file.endsWith(".log"));

      const stats = await Promise.all(
        logFiles.map(async (file) => {
          const filePath = path.join(this.logDir, file);
          const stat = await fs.promises.stat(filePath);
          return {
            file,
            size: stat.size,
            created: stat.birthtime,
            modified: stat.mtime,
          };
        })
      );

      return stats;
    } catch (error) {
      console.error("Failed to get log stats:", error.message);
      return [];
    }
  }
}

// Usage example
async function demonstrateLogger() {
  const logger = new FileLogger();

  // Log some entries
  await logger.info("Application started", { version: "1.0.0" });
  await logger.warn("This is a warning", { component: "auth" });
  await logger.error("An error occurred", {
    error: "Database connection failed",
  });

  // Get today's logs
  const logs = await logger.getLogs();
  console.log("Today's logs:", logs);

  // Get log file statistics
  const stats = await logger.getLogStats();
  console.log("Log file stats:", stats);
}

// Export for use in other modules
module.exports = FileLogger;

// Run demonstration if this file is executed directly
if (require.main === module) {
  demonstrateLogger().catch(console.error);
}

Best Practices

1. Always Use Asynchronous APIs

javascript
// ❌ Bad - blocks the event loop
const data = fs.readFileSync("large-file.txt");

// ✅ Good - non-blocking
fs.readFile("large-file.txt", (err, data) => {
  // Handle result
});

// ✅ Even better - modern async/await
const data = await fs.promises.readFile("large-file.txt");

2. Handle Errors Properly

javascript
// ❌ Bad - unhandled errors
fs.readFile("file.txt", (err, data) => {
  console.log(data.toString());
});

// ✅ Good - proper error handling
fs.readFile("file.txt", (err, data) => {
  if (err) {
    if (err.code === "ENOENT") {
      console.log("File not found");
    } else {
      console.error("Error reading file:", err.message);
    }
    return;
  }
  console.log(data.toString());
});

3. Use Path Module for Cross-Platform Compatibility

javascript
// ❌ Bad - platform-specific
const filePath = "logs/app.log";

// ✅ Good - cross-platform
const filePath = path.join("logs", "app.log");

4. Validate Input and Handle Edge Cases

javascript
function safeReadFile(filename) {
  if (!filename || typeof filename !== "string") {
    throw new Error("Filename must be a non-empty string");
  }

  const normalizedPath = path.normalize(filename);

  // Prevent directory traversal attacks
  if (normalizedPath.includes("..")) {
    throw new Error("Invalid file path");
  }

  return fs.promises.readFile(normalizedPath, "utf8");
}

5. Use Streams for Large Files

javascript
// For large files, use streams instead of reading everything into memory
const fs = require("fs");
const readline = require("readline");

async function processLargeFile(filename) {
  const fileStream = fs.createReadStream(filename);
  const rl = readline.createInterface({
    input: fileStream,
    crlfDelay: Infinity,
  });

  for await (const line of rl) {
    // Process each line without loading entire file into memory
    console.log(line);
  }
}

Summary

Node.js core modules provide essential functionality for:

  • File System (fs): Reading, writing, and manipulating files and directories
  • Path: Cross-platform path manipulation and resolution
  • HTTP: Creating servers and making HTTP requests
  • OS: Accessing operating system information and utilities
  • URL: Parsing and manipulating URLs

Key principles:

  • Always prefer asynchronous APIs to avoid blocking the event loop
  • Handle errors appropriately with proper error checking
  • Use path module for cross-platform file path handling
  • Validate inputs and handle edge cases
  • Consider using streams for large data processing

These core modules form the foundation for building robust Node.js applications. Next, we'll explore how to create HTTP servers and build our first web applications.

PreviousNPM: Node Package Manager FundamentalsNextCreating HTTP Servers with Node.js

Open source, free forever. Built by iammhador.

Contribute on GitHub