Module IV · Part 1 — The Invisible Half
Backend & REST
The frontend is the face. The backend is the mind — receiving, processing, storing, and responding. Every click hides a conversation. Here, you learn its language.
Section 1 — The Invisible Architecture
What is a Backend?
Think of a restaurant. The frontend is the dining area — menus, waitstaff, the table you sit at. The backend is the kitchen — where orders are processed, food is prepared, and the real work happens. Guests never see the kitchen, but every meal depends on it.
What the user sees and touches. Runs inside the browser on the user's device.
- • HTML, CSS, JavaScript
- • Sends HTTP requests to the server
- • Displays the data it receives back
- • Examples: React, Vue, plain HTML pages
What processes and responds. Runs on a remote machine 24/7.
- • Node.js, Python, Java, Go, PHP
- • Applies your business logic
- • Connects to databases
- • Returns structured data — usually JSON
Section 1 — Continued
Core Responsibilities
Every backend server handles five core duties on each request. Understanding these gives you a mental model for any backend system you encounter.
Listens for incoming requests from browsers, mobile apps, or other servers. Each request has a method (GET, POST…) and a URL.
Reads and stores data in databases — MySQL, MongoDB, PostgreSQL, SQLite. The backend is the only layer that should touch the database directly.
Applies logic: "users can only edit their own posts", "free accounts have a 5 upload limit", input validation, rate limiting.
Verifies who the user is (authentication) and what they are allowed to do (authorisation). Usually via tokens or sessions.
Sends JSON back to the frontend — success data, error messages, and an HTTP status code that tells the client what happened.
Same language as the frontend. Fast, non-blocking I/O. Our choice for this module.
Great for data-heavy apps. Popular frameworks: Django, FastAPI, Flask.
Enterprise-grade, robust and mature. Main framework: Spring Boot.
Go excels at performance & concurrency. PHP powers a huge portion of legacy web.
Section 2 — The Universal Tongue
REST API
REST stands for Representational State Transfer. It is a set of design principles for building web APIs — a shared convention so different systems can communicate over HTTP without custom agreements.
Each request must carry all the information the server needs. No session is stored between calls — the server treats every request as brand new.
Everything is a "resource" — a user, a post, an order. Each resource is identified by a URL: /api/users/42 is user number 42.
Actions are expressed using HTTP verbs: GET to read, POST to create, PUT to replace, PATCH to update part, DELETE to remove.
Responses are structured as JSON — a lightweight text format that both humans and machines can read and parse easily.
// The browser (client) sends a request:
GET /api/users/42 HTTP/1.1
Host: api.example.com
// The server responds with JSON:
{
"success": true,
"data": { "id": 42, "name": "Alice", "email": "[email protected]" }
}Section 2 — The Verbs of Creation
HTTP Methods
Five verbs. Every REST operation maps to one of them. Memorise these — they are the foundation of every API you will ever build or use.
Fetches a resource without changing anything. Safe and idempotent — calling it ten times has the same result as calling it once.
GET /api/usersSends data in the request body to create a new record. Returns the created resource with a 201 status code.
POST /api/usersReplaces an entire resource with the new data you provide. If you omit a field, it may be cleared.
PUT /api/users/42Updates only the fields you specify. The rest of the resource stays unchanged. More surgical than PUT.
PATCH /api/users/42Permanently removes the resource identified by the URL. Returns 200 OK or 204 No Content.
DELETE /api/users/42Section 2 — REST in Practice
API Design
Here is what a well-designed REST API looks like for a Users resource. Notice how the same URL /api/users/:id is reused with different HTTP methods to perform different actions.
| METHOD | ENDPOINT | DESCRIPTION |
|---|---|---|
| GET | /api/users | Return all users |
| GET | /api/users/:id | Return one user by ID |
| POST | /api/users | Create a new user |
| PUT | /api/users/:id | Replace full user data |
| DELETE | /api/users/:id | Delete user by ID |
Common HTTP Status Codes
Request worked. Data returned.
New resource was created.
Success — nothing to return.
Client sent malformed data.
Authentication required.
Logged in, but not allowed.
Resource does not exist.
Something broke server-side.
Section 3 — The Forge
Project Setup
Before writing a single route, you need your environment ready. Three terminal commands and a file — that is all it takes to have a live server.
Prerequisites — Check these before starting
- ✦Node.js installed— run node --version → should show v18 or higher
- ✦npm (Node Package Manager)— comes bundled with Node.js automatically
- ✦A code editor— VS Code is free and highly recommended
- ✦Postman app installed— download free at postman.com — used in Section 5
Create your project folder
Install Express
Express is a minimal, flexible web framework for Node.js. It handles routing and middleware so you can focus on your logic.
Create the entry file
Create index.js in your project root. This is where your server will live.
Project structure after setup
Section 4 — The Incantation
Building the API
A complete Users API with all five CRUD operations. Data lives in-memory as a plain JavaScript array — no database setup required. Focus entirely on the API structure and how Express routing works.
// 1. Import Express and create the app instance
const express = require('express');
const app = express();
const PORT = 3000;
// 2. Middleware — tells Express to parse incoming JSON request bodies
// Without this, req.body will be undefined on POST and PUT requests
app.use(express.json());
// 3. In-memory data store — simulates a database using a plain array
// In a real app you would replace this with actual database calls
let users = [
{ id: 1, name: 'Alice', email: '[email protected]' },
{ id: 2, name: 'Bob', email: '[email protected]' },
];
let nextId = 3; // tracks the next available ID// ── GET /api/users ─────────────────────────────────────────────
// Returns the full list of users as JSON
app.get('/api/users', (req, res) => {
res.json({ success: true, data: users });
});
// ── GET /api/users/:id ──────────────────────────────────────────
// :id is a URL parameter — /api/users/2 gives req.params.id = "2"
app.get('/api/users/:id', (req, res) => {
const user = users.find(u => u.id === parseInt(req.params.id));
if (!user) return res.status(404).json({ success: false, message: 'User not found' });
res.json({ success: true, data: user });
});
// ── POST /api/users ─────────────────────────────────────────────
// req.body contains the JSON you sent in the request body
app.post('/api/users', (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ success: false, message: 'Name and email are required' });
}
const newUser = { id: nextId++, name, email };
users.push(newUser);
res.status(201).json({ success: true, data: newUser });
});
// ── PUT /api/users/:id ──────────────────────────────────────────
// Replaces the entire user object (preserving the original ID)
app.put('/api/users/:id', (req, res) => {
const index = users.findIndex(u => u.id === parseInt(req.params.id));
if (index === -1) return res.status(404).json({ success: false, message: 'User not found' });
users[index] = { id: users[index].id, ...req.body };
res.json({ success: true, data: users[index] });
});
// ── DELETE /api/users/:id ───────────────────────────────────────
// Filters out the user with the matching ID from the array
app.delete('/api/users/:id', (req, res) => {
const before = users.length;
users = users.filter(u => u.id !== parseInt(req.params.id));
if (users.length === before) return res.status(404).json({ success: false, message: 'User not found' });
res.json({ success: true, message: 'User deleted' });
});// 4. Start listening for incoming requests on PORT 3000
app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});
req.paramsValues captured from the URL — /users/:id gives you req.params.id
req.bodyThe JSON payload sent by the client — only available after express.json() middleware
res.status()Sets the HTTP status code before sending — chain with .json() to respond
Section 5 — The Mirror
Testing with Postman
Postman lets you send HTTP requests to your API from a visual interface — no code required. Use it to verify every route works before you connect any frontend. Make sure your server is running (node index.js) before testing.
http://localhost:3000/api/users{ "success": true, "data": [ { "id": 1, ... }, { "id": 2, ... } ] }http://localhost:3000/api/users/1{ "success": true, "data": { "id": 1, "name": "Alice", "email": "..." } }http://localhost:3000/api/users{ "name": "Charlie", "email": "[email protected]" }{ "success": true, "data": { "id": 3, "name": "Charlie", ... } }http://localhost:3000/api/users/1{ "name": "Alice Updated", "email": "[email protected]" }{ "success": true, "data": { "id": 1, "name": "Alice Updated", ... } }http://localhost:3000/api/users/1{ "success": true, "message": "User deleted" }Pro Tip — Save as a Postman Collection
Save all five requests inside a Postman Collection. This lets you re-run your entire test suite in one click after any code change. Name each request clearly: GET All Users, POST New User, and so on. Collections can also be exported and shared with your team.
Codex Final — Harmony
The routes are drawn. The server listens. GET, POST, PUT, DELETE — the verbs of creation echo through the wire. The request flows in. The JSON flows out. The API is alive.
What a backend does, what REST means, HTTP verbs, and status codes.
Init project, install Express, create index.js. Server live in minutes.
Five CRUD routes in a full index.js, verified with Postman.
Part 2 Preview
Next: connect a real database (MongoDB or SQLite), add middleware patterns (error handling, request logging, auth), and manage environment variables with .env files.