Node.js — Files, HTTP, Express

একই JavaScript, কিন্তু এবার server-এ

~50 min Advanced 14 practice problems Live runner

1. Built-in Modules

// ESM imports — package.json: "type": "module"
import { readFile, writeFile } from "node:fs/promises";
import path from "node:path";
import os from "node:os";

console.log(os.platform(), os.cpus().length);
console.log(path.join(import.meta.dirname, "data.json"));

const text = await readFile("hello.txt", "utf8");
await writeFile("out.txt", text.toUpperCase());
Node-এ fs/promises, path, os, process — এই কয়টি built-in module-ই দৈনিক কাজের ভিত্তি।

2. Tiny HTTP Server

import { createServer } from "node:http";

const server = createServer((req, res) => {
    if (req.url === "/" && req.method === "GET") {
        res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
        res.end("হ্যালো from Node!");
    } else {
        res.writeHead(404);
        res.end("not found");
    }
});

server.listen(3000, () => console.log("http://localhost:3000"));

3. Express — Less Boilerplate

$ npm install express

import express from "express";
const app = express();
app.use(express.json());                  // parse JSON bodies

app.get("/", (req, res) => res.send("hi"));
app.get("/users/:id", (req, res) => res.json({ id: req.params.id }));
app.post("/users", (req, res) => {
    const u = { id: Date.now(), ...req.body };
    res.status(201).json(u);
});

app.listen(3000, () => console.log("up on 3000"));

4. A Tiny REST API — Todos

import express from "express";
const app = express();
app.use(express.json());

let todos = [{ id: 1, text: "buy chal", done: false }];

app.get("/todos",      (req, res) => res.json(todos));
app.get("/todos/:id",  (req, res) => {
    const t = todos.find(x => x.id === +req.params.id);
    if (!t) return res.status(404).json({ error: "not found" });
    res.json(t);
});
app.post("/todos", (req, res) => {
    const t = { id: Date.now(), text: req.body.text, done: false };
    todos.push(t);
    res.status(201).json(t);
});
app.patch("/todos/:id", (req, res) => {
    const t = todos.find(x => x.id === +req.params.id);
    if (!t) return res.sendStatus(404);
    Object.assign(t, req.body);
    res.json(t);
});
app.delete("/todos/:id", (req, res) => {
    todos = todos.filter(x => x.id !== +req.params.id);
    res.sendStatus(204);
});

app.listen(3000);

5. Sandbox-Safe API Simulation

The runner can't open ports, but the same data layer runs perfectly here.

api.js
let todos = [{ id: 1, text: "buy chal", done: false }];

const api = {
    list() { return todos; },
    get(id) { return todos.find(t => t.id === id) || null; },
    create(text) {
        const t = { id: Date.now(), text, done: false };
        todos.push(t);
        return t;
    },
    update(id, patch) {
        const t = this.get(id);
        if (!t) return null;
        Object.assign(t, patch);
        return t;
    },
    remove(id) {
        const before = todos.length;
        todos = todos.filter(t => t.id !== id);
        return before !== todos.length;
    }
};

const a = api.create("finish ABCL course");
api.update(a.id, { done: true });
console.log(api.list());

6. Middleware

// Logging
app.use((req, res, next) => {
    console.log(req.method, req.url);
    next();
});

// Auth gate
app.use("/api", (req, res, next) => {
    if (!req.headers.authorization) return res.sendStatus(401);
    next();
});

// Error handler — must take 4 args
app.use((err, req, res, next) => {
    console.error(err);
    res.status(500).json({ error: "internal" });
});

7. Reading Environment Variables

// .env file (use `dotenv`)
DATABASE_URL=postgres://...
PORT=3000

// app.js
import "dotenv/config";
const port = process.env.PORT || 3000;
app.listen(port);
Never commit .env Add it to .gitignore. Provide a .env.example with empty values for new contributors.

8. Glossary (শব্দকোষ)

TermMeaningবাংলায়
Node.jsJavaScript runtime built on V8 + libuv for I/O.V8 + libuv দিয়ে তৈরি JS runtime।
libuvThe C library that gives Node async file/network I/O.Node-কে async I/O দেয় এই C library।
fs/promisesAsync filesystem API based on Promises.Promise-based async fs API।
httpBuilt-in HTTP server / client module.Built-in HTTP server/client module।
ExpressMost popular Node web framework — middleware + routes.Node-এর জনপ্রিয় web framework।
MiddlewareFunction with (req, res, next) running in a chain.(req, res, next) পদ্ধতির chain function।
RESTHTTP-based API style: GET/POST/PATCH/DELETE on resources.Resource-এ GET/POST/PATCH/DELETE — REST style।
process.envEnvironment variables — config & secrets.Environment variable — config ও secret।
Reverse proxyServer (e.g. nginx) in front of Node for TLS, gzip, load balancing.Node-এর সামনে nginx — TLS/gzip/load-balance।
Graceful shutdownStop accepting new connections; finish in-flight ones; exit.নতুন connection বন্ধ → চলমান শেষ → exit।
সংক্ষেপে: Node = V8 + libuv + rich standard library। REST API-এর জন্য Express; middleware-এ cross-cutting (log, auth, error)। Config .env-এ — কখনোই commit করবেন না। Production-এ nginx-এর পেছনে রাখুন এবং SIGINT-এ graceful shutdown করুন।

9. Practice Problems

  1. Write a runnable in-memory CRUD store for "books".
    ✨ Show Answer
    a1.js
    const books = [];
    const add  = (t) => books.push({ id: books.length + 1, t });
    add("পথের পাঁচালী"); add("আগুনের পরশমণি");
    console.log(books);
  2. Sketch a GET /books endpoint in Express.
    ✨ Show Answer
    app.get("/books", (req, res) => res.json(books));
  3. Why use express.json() middleware?
    ✨ Show Answer

    Answer: It parses incoming JSON bodies and attaches them to req.body. Without it, req.body is undefined for JSON requests.

  4. Add a 404 handler.
    ✨ Show Answer
    app.use((req, res) => res.status(404).json({ error: "not found" }));
  5. Read process arguments.
    ✨ Show Answer
    // node app.js hello world
    console.log(process.argv.slice(2));   // ["hello", "world"]
  6. Use fs/promises to read a JSON file (sketch).
    ✨ Show Answer
    import { readFile } from "node:fs/promises";
    const cfg = JSON.parse(await readFile("config.json", "utf8"));
  7. Why is Node single-threaded yet good for I/O?
    ✨ Show Answer

    Answer: Node uses libuv to push I/O onto a thread pool while JS itself runs single-threaded. Your code never blocks waiting for disk or network — callbacks/Promises fire when the result arrives. Result: thousands of concurrent connections handled by one process.

  8. Build an Express middleware that logs request time.
    ✨ Show Answer
    app.use((req, res, next) => {
        const t0 = Date.now();
        res.on("finish", () => console.log(req.method, req.url, Date.now() - t0, "ms"));
        next();
    });
  9. Add CORS headers manually (sketch).
    ✨ Show Answer
    app.use((req, res, next) => {
        res.setHeader("Access-Control-Allow-Origin", "*");
        res.setHeader("Access-Control-Allow-Methods", "GET,POST,PATCH,DELETE");
        res.setHeader("Access-Control-Allow-Headers", "Content-Type,Authorization");
        if (req.method === "OPTIONS") return res.sendStatus(204);
        next();
    });
  10. Build a runnable validate(body) helper for {text required}.
    ✨ Show Answer
    a10.js
    const validate = b => {
        if (!b || typeof b.text !== "string" || !b.text.trim())
            return { ok: false, error: "text required" };
        return { ok: true };
    };
    console.log(validate({}));
    console.log(validate({ text: "hi" }));
  11. Why do production apps put Node behind a reverse proxy (nginx)?
    ✨ Show Answer

    Answer: nginx terminates TLS, serves static files faster, gzip-compresses, rate-limits, and load-balances multiple Node processes. It's also far better at gracefully handling slow clients than Node's built-in HTTP server.

  12. Add a graceful shutdown on SIGINT (sketch).
    ✨ Show Answer
    const server = app.listen(3000);
    process.on("SIGINT", () => {
        console.log("shutting down");
        server.close(() => process.exit(0));
    });
  13. Demonstrate an in-memory rate-limiter (logic only).
    ✨ Show Answer
    a12.js
    function limiter(maxPerMin) {
        const hits = new Map();
        return ip => {
            const now = Date.now();
            const arr = (hits.get(ip) || []).filter(t => now - t < 60_000);
            arr.push(now);
            hits.set(ip, arr);
            return arr.length <= maxPerMin;
        };
    }
    const ok = limiter(2);
    console.log(ok("ip1"), ok("ip1"), ok("ip1"));
  14. In one paragraph, why is Node so popular for backends in 2026?
    ✨ Show Answer

    Answer: One language end-to-end, the largest package ecosystem (npm), brilliant async I/O performance, and a tiny memory footprint per connection. Hire one engineer, they ship both ends. The big trade-off — single-threaded CPU per process — is worked around with worker threads or cluster mode when needed.

Summary — Module 38

Node = V8 + libuv + a rich standard library. Built-in http for raw work; Express for ergonomics. Compose with middleware. Read config from env vars. Don't commit .env. Behind a reverse proxy in production.

Node দিয়ে JS server-এ চলে। Express কম boilerplate-এ REST API দেয়। Middleware দিয়ে cross-cutting কাজ। Production-এ nginx-এর পেছনে রাখুন।

Next Module → Frameworks Survey — React, Vue, Svelte।