NodeJs



Overview


Simplest NodeJs Server

const { createServer } = require('node:http')
//import { createServer } from 'node:http' 
//If you use import instead require, you need to add this in package.json ->"type": "module",

const hostname = '127.0.0.1'
const port = 3000

const server = createServer((req, res) => {
    res.statusCode = 200
    res.setHeader('Content-type', 'text/plain')
    res.end('Hello World')
})

server.listen(port, hostname, () => { console.log(`server is running a http://${hostname}:${port}/`) })

Modules


(function(exports, require, module, __filename, __dirname) {
    // Module code
});

IIFE - Immediately Invoked Function Expression


(function (exports, require, module, __filename, __dirname) {
    // Your module code here
})();

CommonJS Modules



// math.js - Multiple exports using module.exports object
module.exports = {
  add: function(a, b) {
    return a + b;
  },
  subtract: function(a, b) {
    return a - b;
  }
};

//imports
const math = require('./math');
console.log(math.add(5, 3));      // 8
console.log(math.subtract(5, 3)); // 2

// math.js - Named Exports
function add(a, b) {
  return a + b;
}
module.exports.add = add; || module.exports = {add, subtract};

// imports
const math = require('./math');
let result = math.add(a, b); || const { add, subtract } = require('./math');

// math.js - Default Export
function anotherFunction(a, b) {
  return a * b;
}
module.exports = anotherFunction;

// imports
const math = require('./math');
const add = math;

ES modules (Node ≥ 14.0.0)


//Exports
export { add, subtract };
export default class User {}

//Imports
import { add, subtract } from './math.mjs';
import User from './user.js';

#Named vs Namespace Imports
// Named imports (specific exports)
import { add, subtract } from './math.js';

// Namespace import (all exports as an object)
import * as math from './math.js';
console.log(math.add(5, 3));

Top-level await

// data.js
export const data = await fetch('https://api.example.com/data')
  .then(response => response.json());

// app.js
import { data } from './data.js';
// data is already resolved when imported
console.log(data);

Path Module


const path = require('path'); //For common
import path from 'path'; //For ES

//Properties
path.sep
path.delimiter

//Methods
path.basename(path, [,ext]) //if the extension is provided, file name return without an extention
path.dirname(path) //return only dirname
path.extname(path) //console.log(path.extname('index.html')); //.html
path.format(pathObj)
path.isAbsolute(path)
path.join(...path) //console.log(path.join('/home', 'js', 'dist', 'app.js')) //\home\js\dist\app.js
path.normalize(path)
path.parse(path) //return an object -> path.parse("c://mad/react/app.js").basename)
path.relative(from, to)
path.resolve(...path)

FS Module


Promise API

import * as fs from "fs/promises"
import * as fs from "fs/promises"

try{
    //create directory
    await fs.mkdir("/home/madusanka/DEVS") //path should be correct and exist
    await fs.mkdir("/home/madusanka", {recursive:true}) //now the folder is created even if the parent folder not exists
    
    //read a directory
    const files = await fs.readdir("/home/madusanka/DEVS")
    for(const file of files){
        console.log(file)
    }

    //remove directory (directory should be empty)
    await fs.rmdir("/home/madusanka/DEVS/fs")

    //Create and write file
    await fs.writeFile("/home/madusanka/DEVS/abc.txt", "Hello World") //override file content if exist

    //Read file
    const data = await fs.readFile("/home/madusanka/DEVS/abc.txt", "utf-8")
    console.log(data);

    //Append file
    await fs.appendFile("/home/madusanka/DEVS/abc.txt", "\nnew content")

    //Copying file (destination file will be created if not present)
    await fs.copyFile("/home/madusanka/DEVS/abc.txt", "/home/madusanka/DEVS/abcd.txt")
 
}catch(error){
    console.log(error)
}

Callback API

import * as fs from "fs"

fs.mkdir("/home/intervest/DEVS/FS Module/new directory", function(error, data){
    if(error) throw error;
})

Sync APi

import * as fs from "fs"
fs.mkdirSync("/home/intervest/DEVS/FS Module/new directory", {recursive:true})

Os Module


const os = require('os');
import os from 'os';

os.type()
os.arch() //x64
os.platform() //win32
os.release()
os.version()
os.uptime()
os.userInfo()
os.totalmem()
os.freemem()
os.cpus() //cpu as an object
os.networkInterfaces()

URL Module


import {URL} from 'url'

const myUrl = new URL("https://yahoo.com:8080?query=someQuery#someHash")

console.log(myUrl.hash)
console.log(myUrl.host)
console.log(myUrl.hostname)
console.log(myUrl.port)
console.log(myUrl.href)
console.log(myUrl.protocol)
console.log(myUrl.search)
console.log(myUrl.searchParams)

//Both works same
console.log(myUrl.toString())
console.log(myUrl.toJSON())

Event Module


const EventEmitter = require('events');
//import EventEmitter from  'events';

const emitter = new EventEmitter();

emitter.on('saved', (arg) => {
    console.log(`A saved event occurred.`);
});

emitter.once('onetime', (arg) => {
    console.log(`This will be emited only one time, no matter how much time called.`);
});

emitter.emit('saved',{...someData});//A saved event occurred.

// remove the event listener
emitter.off('saved', log); //After removing, no effect on reemiting the same event
class Stock extends EventEmitter {....code}

HTTP Module


import http from 'http'

const server = http.createServer((req,res)=>{
    // console.log(req)
    res.setHeader("Content-Type", "text/html")
    res.statusCode = 404
    res.statusMessage = "BAD"

    //Short way
    res.writeHead(202,"Good", {"Content-Type": "text/html"})

    res.write('<h1>Hello from NodeJs</h1>')
})

server.listen(8000, ()=>console.log("Server is Up!"))

Routing


import http from 'http'

const server = http.createServer((req, res) => {
    if (req.url === "/") {
        res.end("<h1>Home</h1>")
    }else if(req.url === "/about"){
        res.end("<h1>About</h1>")
    }else{
        res.end("<h1>Not Found :(</h1>")
    }
})

server.listen(8000, () => console.log("Server is Up!"))

Serving Files


import http from 'http'
import * as fs from 'fs'

const server = http.createServer((req, res) => {
    if (req.url === "/") {
        res.writeHead(200, "Good", { "Content-Type": "text/html" })
        fs.readFile("./public/Home.html", (error, data) => {
            if (error) throw error
            res.end(data)
        })

    } else {
        res.end("<h1>Not Found :(</h1>")
    }
})

server.listen(8000, () => console.log("Server is Up!"))

Process module


SET NODE_ENV=development //Windows
EXPORT NODE_ENV=development //Mac/Linux
process.env.NODE_ENV

Stream



Example: Reading a Large File Using createReadStream


// Step 1: Generate a file with a large dataset
import fs from 'fs';

for (let i = 0; i < 10000; i++) {
  // Append data to 'data.txt'
  fs.writeFileSync("./data.txt", `${i}\n`, { flag: "a" });
}

import { createReadStream } from 'fs';

// Step 2: Read the file using a readable stream
// 'highWaterMark' can be used to set buffer size (in bytes)
// 'encoding' set to 'utf-8' to get string data instead of buffers
const stream = createReadStream("./data.txt", {
  encoding: "utf-8",
  // highWaterMark: 10000 // Optional: customize buffer size
});

// Step 3: Listen to 'data' event to process chunks
stream.on("data", (chunk) => {
  console.log(chunk); // Logs each chunk of data
});

'data' — when a chunk is available 'end' — when the stream ends 'error' — if something goes wrong 'close' — when the stream is closed


ExpressJs


const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

Routing


app.get('/', (req, res) => {
  res.send('Hello World!')
})

Route paths


app.get('/ab?cd', (req, res) => { }) //match acd and abcd.
app.get('/ab+cd', (req, res) => { }) //match abcd, abbcd, abbbcd, and so on.
app.get('/ab*cd', (req, res) => { }) //match abcd, abxcd, abRANDOMcd, ab123cd, and so on.
app.get('/ab(cd)?e', (req, res) => { }) //match /abe and /abcde.
app.get('/a/', (req, res) => { }) //match anything with an “a” in it.
app.get('/.*fly$/', (req, res) => { }) //match butterfly and dragonfly, but not butterflyman, dragonflyman, and so on.

Route parameters


app.get('/users/:userId/books/:bookId', (req, res) => {})
Route path: /user/:userId(\d+)
Request URL: http://localhost:3000/user/42
req.params: {"userId": "42"}

Route handlers


const cb0 = function (req, res, next) {
  console.log('CB0')
  next() //Passing controll no next middleware or handler
}

const cb1 = function (req, res, next) {
  console.log('CB1')
  next() //Passing controll no next middleware or handler
}

app.get('/example/d', [cb0, cb1], (req, res, next) => {
  console.log('the response will be sent by the next function ...')
  next()
}, (req, res) => {
  res.send('Hello from D!')
})

app.route()


app.route('/book')
  .get((req, res) => {
    res.send('Get a random book')
  })
  .post((req, res) => {
    res.send('Add a book')
  })
  .put((req, res) => {
    res.send('Update the book')
  })

express.Router


#Birds.js

const express = require('express') //or import if you use "type":"module" in nearest parent package.json
const router = express.Router()

//if the parent route /birds has path parameters, To make them accessible from the sub-routes.
const router = express.Router({ mergeParams: true }) 

// middleware that is specific to this router
const timeLog = (req, res, next) => {
  console.log('Time: ', Date.now())
  next()
}
router.use(timeLog)

// define the home page route
router.get('/', (req, res) => {
  res.send('Birds home page')
})
// define the about route
router.get('/about', (req, res) => {
  res.send('About birds')
})

//route handlers can be moved into separate controllers if you wish

module.exports = router ////or export default router, if you use "type":"module" in nearest parent package.json

# app.js
const birds = require('./birds') //or import if you use "type":"module" in nearest parent package.json
app.use('/birds', birds)

Serving static files


app.use(express.static('public'))
app.use(express.static('files'))
app.use('/static', express.static('public')) //To create a virtual path prefix
//path is relative to the directory from where you launch your node process
//If you run the express app from another directory, it’s safer to use the absolute path of the directory that you want to serve
app.use('/static', express.static(path.join(__dirname, 'public')))

Middlewares


app.get('/user/:id', (req, res, next) => {
  // if the user ID is 0, skip to the next route
  if (req.params.id === '0') next('route')
  // otherwise pass the control to the next middleware function in this stack
  else next()
}, (req, res, next) => {
  // send a regular response
  res.send('regular')
})

// handler for the /user/:id path, which sends a special response
app.get('/user/:id', (req, res, next) => {
  res.send('special')
})

//Error-handling middleware
app.use((err, req, res, next) => {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})

Template Engins


npm install ejs

#index.js
import { router as viewRouter } from './routes/views.js'
const app = express();
app.set('view engine', 'ejs'); // Set the view engine to EJS
app.use('/views', viewRouter); // This will handle requests to /views

#routes/views.js
import express from 'express'
import { homePage } from '../controllers/views.js';

const router = express.Router()
router.get('/home', homePage);
export { router };

#controllers/views.js
const homePage = (req, res, next) => {
    res.render('index'); // Render the index view in the views folder
}
export { homePage };

#create a `views` directory in the root folder and add index.html with simple html template, now go to the
#http://localhost:5000/views/home and you can see the html file