β Software Engineering guides
HSC Software Engineering Module 2 Programming for the Web deep dive
Deep dive on HSC Software Engineering Module 2, Programming for the Web. The client-server model, HTTP and HTTPS, front-end HTML/CSS/JavaScript, server-side programming, relational databases and SQL, REST APIs and JSON, with worked exam examples.
Jump to a section
How Module 2 fits into HSC Software Engineering
Programming for the Web is Module 2 of Year 12 Software Engineering, and it is the most practical module. It builds the full stack: how a browser talks to a server, how the front end is structured, how the server handles requests and talks to a database, and how systems exchange data through APIs. It reuses the security ideas from Module 1 (Secure Software Architecture) whenever it touches web vulnerabilities, and a small full-stack project for this module also covers much of the Software Engineering Project module.
This guide walks through the client-server model, HTTP and HTTPS, the front end, server-side programming, relational databases and SQL, and REST APIs with JSON, with worked examples in the style NESA uses.
The client-server model and the request-response cycle
The web is built on clients (browsers) requesting resources from servers.
HTTP is stateless: the server does not remember previous requests on its own. Identity is carried across requests using sessions (a session id in a cookie) or tokens (such as a signed JWT sent in a header). Forgetting that HTTP is stateless is a common source of confusion in exam answers about logins.
HTTP and HTTPS
An HTTP request has a method and a URL. The common methods map to actions:
| Method | Use |
|---|---|
| GET | Retrieve a resource (no side effects) |
| POST | Create a resource or submit data |
| PUT / PATCH | Update a resource (replace / partial) |
| DELETE | Remove a resource |
Responses carry a status code. Know the families: 2xx success (200 OK, 201 Created), 3xx redirection (301 permanent, 302 temporary), 4xx client error (400 bad request, 401 unauthenticated, 403 forbidden, 404 not found), and 5xx server error (500 internal error).
The front end: HTML, CSS and JavaScript
The front end has three layers with distinct jobs. HTML provides structure and meaning (semantic elements such as header, nav, main, article). CSS provides presentation (layout, colour, typography). JavaScript provides behaviour (responding to events, updating the page, and calling APIs).
Separating these concerns keeps code maintainable. JavaScript running in the browser can validate input for quick user feedback, but as Module 1 stresses, that validation is a convenience only: the server must validate everything again because client-side checks can be bypassed.
// Front-end: call a REST API and render the result
async function loadNotes() {
const response = await fetch("/api/notes");
if (!response.ok) {
console.error("Request failed:", response.status);
return;
}
const notes = await response.json();
const list = document.querySelector("#notes");
// Use textContent (not innerHTML) to avoid injecting markup
for (const note of notes) {
const li = document.createElement("li");
li.textContent = note.title;
list.appendChild(li);
}
}
Note the use of textContent rather than innerHTML. Inserting untrusted data with innerHTML is how cross-site scripting happens; assigning to textContent treats the data as text, not markup.
Server-side programming
The server receives the request, applies business logic, talks to the database, and returns a response. Server-side code is where security is actually enforced: authentication, authorisation, validation, and safe database access all live here. The example below is a Python (Flask) route that lists a user's notes.
@app.get("/api/notes")
def list_notes():
user = current_user(request.headers) # authenticate
if user is None:
return ("Unauthorised", 401)
rows = db.execute(
"SELECT id, title FROM notes WHERE owner_id = ?",
(user.id,), # parameterised: data, not code
)
return jsonify([dict(r) for r in rows])
The route authenticates first, returns 401 if there is no valid user, and uses a parameterised query so the user id is bound as data. It also filters by owner_id, an object-level authorisation check that stops one user reading another user's notes.
Relational databases and SQL
A relational database stores data in tables with rows and columns, linked by keys. A primary key uniquely identifies a row; a foreign key references a primary key in another table to model relationships.
A worked query joining two tables and aggregating:
SELECT s.name, COUNT(e.course) AS course_count
FROM students s
INNER JOIN enrolments e ON e.student_id = s.id
GROUP BY s.id
HAVING COUNT(e.course) >= 2
ORDER BY course_count DESC;
This lists each student with two or more enrolments, most-enrolled first. Two traps to remember: use HAVING (not WHERE) to filter on an aggregate, because WHERE filters rows before grouping and HAVING filters groups after; and an INNER JOIN drops students with no enrolments, whereas a LEFT JOIN keeps them.
REST APIs and JSON
A REST API exposes resources at URLs and uses HTTP methods and status codes to operate on them. It is stateless, so each request carries everything the server needs (such as an auth token). JSON is the usual data format because it is lightweight, readable, and maps cleanly onto objects in almost every language.
{
"id": 42,
"title": "Revise OWASP Top 10",
"done": false,
"tags": ["module-1", "security"]
}
A request to create this note would be POST /api/notes with the JSON in the body; a successful response would carry status 201 Created and the new resource. Reading it would be GET /api/notes/42; deleting it would be DELETE /api/notes/42. The clean mapping of methods to actions and resources to URLs is what makes an API "RESTful".
Common Module 2 examiner traps
- Forgetting HTTP is stateless when explaining logins.
- Confusing status code families (for example 401 unauthenticated versus 403 forbidden).
- Using
innerHTMLwith untrusted data (cross-site scripting). - Using
WHEREwhereHAVINGis required, orINNER JOINwhereLEFT JOINis required. - Building SQL by string concatenation instead of parameterised queries.
Check your knowledge
Answer all questions under exam conditions, then mark against the solutions block.
- (3 marks) Describe the request-response cycle for a browser loading a dynamic page, and explain what it means for HTTP to be stateless.
- (3 marks) State what each of the status codes 200, 301, 404 and 500 means, and give one situation that would produce each.
- (4 marks) Read this query. Explain what it returns, identify whether it should use
WHEREorHAVINGto filter for totals over 100, and rewrite it correctly.
SELECT customer_id, SUM(amount) AS total
FROM orders
GROUP BY customer_id;
- (4 marks) A front-end developer renders user comments with
element.innerHTML = comment. Identify the vulnerability, explain how it is exploited, and describe the fix. - (5 marks) Design a small REST API for a to-do list. Give the URL and HTTP method for creating a task, reading one task, updating a task, and deleting a task, and state the success status code each returns. Explain why JSON is a suitable data format.
Where to go next
Test these ideas in exam format with our HSC Software Engineering practice questions, and revise the security side in the Secure Software Architecture deep dive. For dot-point answers, browse the full syllabus index.
For the official syllabus, refer to NESA at educationstandards.nsw.edu.au.