Node.js & Express Basics

Build server-side web applications with Node.js and the Express framework — routes, middleware, request handling, and JSON APIs.

Hard 75m 3 tasks

Learning Objectives

  • Understand Node.js's event loop and non-blocking I/O
  • Create a basic HTTP server with Node's http module
  • Build routes and middleware with Express
  • Parse request bodies and return JSON responses
  • Handle errors and 404s in Express

What is Node.js?

Node.js runs JavaScript on the server using Chrome's V8 engine. Key characteristics:
- Single-threaded with an event loop for concurrency
- Non-blocking I/O — handles many connections without threads
- npm — 2M+ packages available

node --version     # v20.x.x
npm --version      # 10.x.x

The Event Loop

   ┌─── timers (setTimeout, setInterval)
      ├─── I/O callbacks (network, file)
      ├─── idle / prepare
      ├─── poll (wait for new I/O events)
      ├─── check (setImmediate)
      └─── close callbacks

Node handles async work by registering callbacks and continuing — never blocking.

Simple HTTP Server (no framework)

const http = require("http");

const server = http.createServer((req, res) => {
  res.writeHead(200, { "Content-Type": "application/json" });
  res.end(JSON.stringify({ host: req.headers.host, url: req.url }));
});

server.listen(3000, () => console.log("Listening on :3000"));

Setting Up Express

mkdir api && cd api
npm init -y
npm install express
// server.js
const express = require("express");
const app     = express();

app.use(express.json());                    // parse JSON bodies
app.use(express.urlencoded({ extended: true })); // parse form bodies

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

Routing

// GET /
app.get("/", (req, res) => {
  res.json({ status: "ok", message: "CyberLearn API" });
});

// GET /scan/:host
app.get("/scan/:host", (req, res) => {
  const { host } = req.params;
  const { port = 80 } = req.query;
  res.json({ host, port: Number(port), scanning: true });
});

// POST /scan
app.post("/scan", (req, res) => {
  const { host, ports } = req.body;
  if (!host) {
    return res.status(400).json({ error: "host is required" });
  }
  // ... perform scan
  res.status(202).json({ queued: true, host, ports });
});

// DELETE /scan/:id
app.delete("/scan/:id", (req, res) => {
  res.json({ deleted: req.params.id });
});

Middleware

Middleware = functions that run between request and response:

// Logger middleware
app.use((req, res, next) => {
  console.log(`${new Date().toISOString()} ${req.method} ${req.url}`);
  next();   // MUST call next() or request hangs
});

// Auth middleware
function requireAuth(req, res, next) {
  const token = req.headers.authorization?.split(" ")[1];
  if (!token || token !== process.env.API_TOKEN) {
    return res.status(401).json({ error: "Unauthorized" });
  }
  next();
}

// Apply to specific route
app.get("/admin", requireAuth, (req, res) => {
  res.json({ admin: true });
});

// Apply to all routes under /api
app.use("/api", requireAuth);

Request Object

req.params       // URL params: /user/:id → req.params.id
req.query        // Query string: ?page=2 → req.query.page
req.body         // Parsed request body (needs express.json())
req.headers      // All request headers
req.method       // "GET", "POST", etc.
req.url          // "/scan?host=10.0.0.1"
req.ip           // Client IP
req.cookies      // Cookies (needs cookie-parser)

Response Object

res.json({ key: "value" })       // send JSON
res.status(201).json({ id: 1 }) // set status + send JSON
res.send("Hello")                // send text
res.sendFile("/path/to/file")    // send file
res.redirect(301, "/new-url")    // redirect
res.set("X-Custom", "value")     // set header
res.cookie("session", "abc")     // set cookie

Error Handling

// 404 handler (after all routes)
app.use((req, res) => {
  res.status(404).json({ error: "Not found", path: req.url });
});

// Error handler (4 args — Express identifies by signature)
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(err.status || 500).json({
    error: err.message || "Internal server error",
  });
});

// Async error forwarding
app.get("/data", async (req, res, next) => {
  try {
    const data = await fetchData();
    res.json(data);
  } catch (err) {
    next(err);   // forward to error handler
  }
});

Mini Project – Scan API

const express = require("express");
const net     = require("net");

const app = express();
app.use(express.json());

async function isOpen(host, port, timeout = 500) {
  return new Promise(resolve => {
    const s = net.createConnection({ host, port });
    s.setTimeout(timeout);
    s.on("connect", () => { s.destroy(); resolve(true);  });
    s.on("error",   () => { s.destroy(); resolve(false); });
    s.on("timeout", () => { s.destroy(); resolve(false); });
  });
}

app.post("/api/scan", async (req, res, next) => {
  try {
    const { host, ports = [22, 80, 443] } = req.body;
    if (!host) return res.status(400).json({ error: "host required" });

    const results = await Promise.all(
      ports.map(async p => ({ port: p, open: await isOpen(host, p) }))
    );
    res.json({ host, results });
  } catch (err) {
    next(err);
  }
});

app.listen(3000, () => console.log("Scan API on :3000"));

Create a new npm project. Install Express. Write server.js with: GET / returning {status:'ok'}, GET /health returning {uptime: process.uptime()}. Start with node server.js and test with curl.

✦ Answer the questions to complete this task

What npm command initializes a new Node.js project?

What Express method registers a GET route handler?

Add a logging middleware that prints METHOD URL IP timestamp for every request. Add a requireAuth middleware that checks for Authorization: Bearer secret123 header. Apply it to a /protected route.

✦ Answer the questions to complete this task

What must middleware call to pass control to the next function?

How many arguments does an Express error handler take?

Implement the mini project scan API. Test with: curl -X POST http://localhost:3000/api/scan -H 'Content-Type: application/json' -d '{"host":"127.0.0.1","ports":[22,80]}'

✦ Answer the questions to complete this task

What does next(err) do in an Express route handler?

💪 Exercises & Challenges

📝 MCQ Medium +20 XP

Node.js & Express MCQ

Node.js & Express MCQ

Start →
⚙️ Practical Medium +30 XP

REST Scan API

REST Scan API

Start →
🚩 Challenge Hard +50 XP

Path Traversal in Express

Path Traversal in Express

Start →