1

JavaScript Basics

JavaScript (JS)

JavaScript is an interpreted, dynamically typed programming language — similar to Python. It can run in the browser, but with Node.js it can also run on the server.

Functions, Variables, and console.log

// A function that takes two arguments
function add(num1, num2) {
  let sum = num1 + num2;
  return sum; // Returns the result
}

let result = add(5, 7); // result is now 12
console.log(result);    // Output: 12

Task

Run the code as-is. Then change the arguments to add(10, 32) and predict the output before running again.

Starter files
basics.js
// A function that takes two arguments
function add(num1, num2) {
  let sum = num1 + num2;
  return sum; // Returns the result
}

let result = add(5, 7); // result is now 12
console.log(result);    // Output: 12
2

JSON — JavaScript Object Notation

JSON (JavaScript Object Notation)

JSON is a human-readable, lightweight data-interchange format used to transfer data between a server and a web page, or between applications.

It is the standard format for REST API responses. In JavaScript, objects look almost identical to JSON:

const person = {
  "address-dict": {
    "city": "New York",
    "residential": true,
    "postal_code": 10023
  },
  "phone_numbers": [
    { "type": "home",   "number": "212 555-1234" },
    { "type": "office", "number": "646 555-4567" }
  ],
  "children": ["Catherine", "Thomas", "Trevor"]
};

Key built-ins

Method Purpose
JSON.stringify(obj) Convert a JS object → JSON string
JSON.parse(str) Parse a JSON string → JS object

Task

Run the code to see JSON serialisation and parsing in action. Notice how JSON.stringify(person, null, 2) pretty-prints the object with 2-space indentation.

Starter files
json-demo.js
const person = {
  "address-dict": {
    "city": "New York",
    "residential": true,
    "postal_code": 10023
  },
  "phone_numbers": [
    { "type": "home",   "number": "212 555-1234" },
    { "type": "office", "number": "646 555-4567" }
  ],
  "children": ["Catherine", "Thomas", "Trevor"]
};

// Serialize JS object → JSON string
const jsonString = JSON.stringify(person, null, 2);
console.log("=== JSON.stringify ===");
console.log(jsonString);

// Parse JSON string back into a JS object
const parsed = JSON.parse(jsonString);
console.log("\n=== Parsed city ===");
console.log(parsed["address-dict"].city); // New York
3

Blocking vs. Non-Blocking I/O

Node.js & the Event Loop

Node.js is a JavaScript runtime for asynchronous events. It is single-threaded, so blocking the main thread means no other requests can be handled.

Blocking Code

const fs = require('fs');

const data = fs.readFileSync('/file.md');
// blocks here until file is read

readFileSync stops execution until the file is fully read. Bad for servers — every other request waits!

Non-Blocking Code (callback style)

fs.readFile('/file.md', (err, data) => {
  if (err) { /* handle error */ }
  // use data here
});
// following code is executed instantly

The callback (err, data) => { ... } is an asynchronous callback: it executes after the data has been completely stored in data. Meanwhile Node.js keeps processing other events.

Named Callbacks

For longer handlers, extract the callback into a named function — this improves readability and enables reuse:

function handleMarkdownRead(err, data) {
  if (err) { /* handle error */ }
  // use data
}

fs.readFile('/file.md', handleMarkdownRead);
// following code is executed instantly

Node.js philosophy: use non-blocking code for all non-instant tasks to maintain high performance and scalability.

Task

Run the code. Notice that "After readFile call" is printed before the file contents — that is the non-blocking nature of Node.js in action.

Starter files
message.txt
Hello from the file system!
This text was read asynchronously.
io-demo.js
const fs = require('fs');

// --- Blocking ---
console.log("=== Blocking readFileSync ===");
const dataSync = fs.readFileSync('message.txt', 'utf8');
console.log(dataSync);
console.log("(This line runs AFTER the file is read)\n");

// --- Non-Blocking (inline callback) ---
console.log("=== Non-Blocking readFile ===");
fs.readFile('message.txt', 'utf8', (err, data) => {
  if (err) {
    console.error("Error:", err.message);
    return;
  }
  console.log("Callback fired:", data);
});
console.log("After readFile call — runs BEFORE callback fires\n");

// --- Named Callback ---
function handleFileRead(err, data) {
  if (err) {
    console.error("Error:", err.message);
    return;
  }
  console.log("Named callback fired:", data);
}

console.log("=== Non-Blocking with named callback ===");
fs.readFile('message.txt', 'utf8', handleFileRead);
console.log("After named callback registration");
4

HTTP Server with Node's http Module

Building an HTTP Server from Scratch

Node.js ships with a built-in http module. You can create a server without any third-party packages:

const http = require('http');
const PORT = 8080;

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello, World!\n');
});

server.listen(PORT, 'localhost', () => {
  console.log(`Server running at http://localhost:${PORT}/`);
});
Line What it does
http.createServer((req, res) => { ... }) Creates an HTTP server; the callback fires on every incoming request
res.writeHead(200, { 'Content-Type': 'text/plain' }) Sets HTTP status 200 (OK) and the Content-Type header
res.end('Hello, World!\n') Writes the response body and closes the connection
server.listen(PORT, 'localhost', callback) Starts listening on port 8080

The callback (req, res) => { ... } passed to createServer is called on every HTTP request — this is Node’s callback pattern applied to networking.

Task

Click ▶ Run to start the server, then use the HTTP Client on the right to send a GET request to http://localhost:8080/ and observe the response.

Starter files
server.js
const http = require('http');
const PORT = 8080;

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello, World!\n');
});

server.listen(PORT, 'localhost', () => {
  console.log(`Server running at http://localhost:${PORT}/`);
});
5

Express.js Routing

Express.js — URL Routing Made Easy

The built-in http module is powerful but low-level. Express is the most popular Node.js web framework. It makes routing simple:

"When someone visits THIS URL with THIS method, call THIS function."

Routes

const express = require('express');
const app = express();
const port = 8080;

// GET /users/:userId  — route parameter
app.get('/users/:userId', (req, res) => {
  res.send(`GET request to user ${req.params.userId}`);
});

// POST /
app.post('/', (req, res) => {
  res.send('POST request to the homepage');
});

// GET /about
app.get('/about', (req, res) => {
  res.send('About page');
});

// Catch-all — must be LAST
app.all('*', (req, res) => {
  res.status(404).send('404 - Page not found');
});

app.listen(port, () => {
  console.log(`Express server listening on port ${port}`);
});
Route Description
app.get('/users/:userId', ...) GET /users/42:userId is a route parameter accessed via req.params.userId
app.post('/', ...) POST / — handles form submissions, data uploads, etc.
app.get('/about', ...) GET /about — static page route
app.all('*', ...) Matches any method and path not matched above — use for 404

app.listen(port, callback) starts the server. Without this line the server never starts — this was the missing piece in the lecture slide code!

Task

Click ▶ Run. The HTTP Client is pre-filled with GET /about. Try also:

Starter files
app.js
const express = require('express');
const app = express();
const port = 8080;

// Route parameter: GET /users/:userId
app.get('/users/:userId', (req, res) => {
  res.send(`GET request to user ${req.params.userId}`);
});

// POST /
app.post('/', (req, res) => {
  res.send('POST request to the homepage');
});

// GET /about
app.get('/about', (req, res) => {
  res.send('About page');
});

// Catch-all 404 handler — must be last
app.all('*', (req, res) => {
  res.status(404).send('404 - Page not found');
});

// app.listen() was missing from the lecture slide — added here!
app.listen(port, () => {
  console.log(`Express server listening on port ${port}`);
});