Theory
The server that never listens
Your 5-line server has one social flaw: it says the same thing to everyone. Ask for the schedule, the seat count, or day 2's events: same greeting.
A real web server READS the question before answering. And the question, you already know from Unit 4's GET lessons, travels in the URL:
localhost:8080/?event=garba&day=2
Everything after the ? is the query string, and today the server finally learns to split and answer it.
Theory
writeHead: label before body
res.writeHead(200, { 'Content-Type': 'text/html' });
The first thing a response declares: the status code (200 OK, 404 Not Found: the very codes your AJAX guard checked!) and headers, chiefly Content-Type:
text/html: the browser renders what follows as a pageapplication/json: the answer is API data: exactly what an AJAX caller's JSON.parse expects
Order law: writeHead comes before any write or end: you cannot label an envelope after it is sealed.
Theory
Splitting the query string
A visit to /?event=garba&day=2 lands in your callback with req.url holding exactly that text. You COULD split it by hand (chop at ?, split on &, split on =), but Node's built-in url module does it properly:
const q = url.parse(req.url, true).query;
url.parse(req.url, true)dissects the URL; the true asks for the query as a parsed OBJECT- its
.queryproperty is then{ event: 'garba', day: '2' }
Note the quotes on '2': query values arrive as strings, the same convert-before-maths rule as every input so far.
Practical
The server that answers the question
const http = require('http');
const url = require('url');
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/html' });
const q = url.parse(req.url, true).query; // split the query string
if (q.event == "garba") {
res.write('<h1>Garba Night</h1>');
res.write('<p>Day ' + q.day + ', Main Ground, 40 seats left</p>');
} else {
res.write('<p>Ask me with ?event=garba&day=2</p>');
}
res.end();
}).listen(8080);
// Visit: localhost:8080/?event=garba&day=2
// Answer: Garba Night, Day 2, Main Ground, 40 seats left
This example runs in Gri-Learn on the web, where you can edit it and see the output.
Quiz
The visitor opens localhost:8080/?event=garba&day=2. What does url.parse(req.url, true).query return?
- The string "?event=garba&day=2", unchanged
- The object { event: 'garba', day: '2' }, with values as strings
- The object { event: 'garba', day: 2 }, with day as a number
- An array: ['garba', '2']
Show the answer
The object { event: 'garba', day: '2' }, with values as strings
With true as the second argument, parse splits the query into a ready object keyed by parameter names: q.event and q.day just work. The subtlety option C misses: values are ALWAYS strings: '2', not 2: URLs carry text, so arithmetic on q.day needs parseInt first, the same lesson TextBoxes and InputBoxes taught. Option A is what req.url gives you BEFORE parsing (well, with the / prefix). Option D loses the names, which are the whole point: parameters answer by name, not position.
Think first
Close the full-stack loop
Unit 4's live search sent xhr.open('GET', 'search.php?q=g'). Rewrite the server side in your head: what should THIS Node server do differently from the listing to serve that AJAX caller: think Content-Type and response format, then tap.
Show the answer
Two changes: writeHead sends application/json (the caller will JSON.parse, not render), and the body becomes a JSON string: filter the events whose names contain q.q, then res.end(JSON.stringify(matches)). The browser side you wrote in Unit 4 needs ZERO changes: its responseText now arrives from YOUR server. That is the full stack in one language: the AJAX engine asks, the event loop answers, JSON in between: and you have personally written every piece of that sentence.
Watch out
Web-server slips
writeHead after write: headers cannot follow body: ERR_HTTP_HEADERS_SENT: label first, always.
Maths on query values: q.day + 1 is '21' territory: parseInt(q.day) first.
Trusting the query blindly: q.event might be missing (undefined) or nonsense: branch defensively, as the listing's else does. Every visitor-supplied value is a guest, not family.
Theory
One lesson left in the subject
The server now listens, splits and answers: but it still remembers nothing: every restart forgets all registrations. The finale gives Node a memory: the fs module: reading, creating, updating, deleting and renaming FILES: registrations written to disk at last, and FestConnect Live complete from XML to a persistent server.
Summary
Key takeaways
- writeHead(status, headers) labels the response BEFORE any body: 200/404, and Content-Type text/html vs application/json.
- The visitor's query string rides req.url: /?event=garba&day=2.
- url.parse(req.url, true).query splits it into a ready object: q.event, q.day.
- Query values are strings: parseInt before arithmetic.
- Branch on the query to answer personally; guard against missing parameters.
- Swap Content-Type to application/json + JSON.stringify, and this server answers Unit 4's AJAX unchanged.
- Memory hook: label the envelope, split the question, answer by name.