How Backend Works — From Request to Response
Most developers understand HTTP and REST in isolation — but struggle to explain what actually happens inside a backend when a user clicks a button. This module traces a real request through every layer of a backend application: router → middleware → controller → service → database → response. You will trace code, debug broken requests, and complete a real enrollment challenge.
1. What Is the Backend?
The application layer between clients and data — not just "the database"
A common beginner mistake is thinking the backend is just "where data is stored." The backend is the application layer — it sits between clients and data, and is responsible for all the logic that makes an application work correctly and securely. The database stores raw data. The backend decides who can access it,what they can see, how it must be validated, and what rulesapply before anything is read or written.
- Runs in the user's browser
- Handles UI rendering and user interaction
- Sends requests to the backend API
- Displays data returned by the backend
- Cannot be trusted for security decisions
- Runs on a server — outside the user's control
- Processes all application logic
- Validates input, checks authentication
- Applies business rules and authorisation
- Reads / writes the database securely
- Returns structured HTTP responses
User opens the platform → Frontend sends
GET /api/courses→ Backend checks authentication → queries database → filters enrolled courses
→ transforms rows into clean JSON → returns 200 OK
→ Frontend renders the course list
The database never speaks directly to the frontend. The backend is the trusted middle layer.
2. The Complete Request Lifecycle
From client click to database and back — every layer explained
When a client sends GET /api/courses/42, it does not go directly to the database. It travels through a precise sequence of layers inside the backend application. Each layer has a specific, non-overlapping responsibility.
method— GET, POST, PUT, DELETEURL + params— /api/courses/42headers— Authorization, Content-Typebody— JSON payload (POST/PUT)query— ?page=1&limit=10
status code— 200, 201, 400, 401, 404, 500headers— Content-Type, CORS headersbody— JSON, HTML, or binary
3. What the Backend Actually Does
Application logic — far more than just database access
Most developers underestimate how much work a backend does per request. The database access is just one step — often the last. Before reaching the database, the backend applies layers of logic that make the application correct, secure, and consistent.
// Incoming: POST /api/orders
// Body: { "productId": 42, "quantity": 2 }
// ── Step 1: Validate input ────────────────────────────────
if (!body.productId || body.quantity < 1) {
return res.status(400).json({ error: 'Invalid order data' });
}
// ── Step 2: Check authentication ──────────────────────────
if (!req.user) {
return res.status(401).json({ error: 'Login required' });
}
// ── Step 3: Apply business rules ──────────────────────────
const product = await productService.getById(body.productId);
if (product.stock < body.quantity) {
return res.status(400).json({ error: 'Insufficient stock' });
}
// ── Step 4: Calculate totals ──────────────────────────────
const total = product.price * body.quantity;
// ── Step 5: Write to database ─────────────────────────────
const order = await orderService.create({
userId: req.user.id,
productId: body.productId,
quantity: body.quantity,
total
});
// ── Step 6: Return response ───────────────────────────────
return res.status(201).json({ orderId: order.id, total });4. Why Frontend Never Talks Directly to the Database
The backend as a controlled access layer
- Any user can query any table
- No authentication enforcement
- Database credentials exposed to browser
- No business rules applied
- Raw database schema visible to users
- Backend decides who can access what
- Credentials never leave the server
- Business rules enforced consistently
- Only safe, transformed data returned
- Internal schema hidden from clients
async function getUser(req, res) {
const targetId = req.params.id;
const currentUser = req.user; // set by authMiddleware
// 1. Authorization check
if (currentUser.id !== targetId && !currentUser.isAdmin) {
return res.status(403).json({ error: 'Forbidden' });
}
// 2. Database query (only this layer touches DB)
const row = await db.users.findById(targetId);
// 3. Select only safe fields — NEVER expose passwordHash
const safeUser = {
id: row.id,
name: row.name,
email: row.email,
createdAt: row.created_at
// passwordHash, internalFlags NOT included
};
return res.status(200).json(safeUser);
}5. Server-Side vs Client-Side
Where each layer runs and what it is responsible for
- Renders HTML, CSS, JavaScript UI
- Handles user interaction (clicks, forms)
- Sends HTTP requests to backend APIs
- Receives and displays response data
- Cannot be trusted for security decisions
- Anyone can inspect or modify the code
- Runs in a controlled server environment
- Processes incoming HTTP requests
- Applies authentication & authorisation
- Enforces all business rules
- Accesses databases and external services
- Returns structured HTTP responses
// BROWSER ──────────────────────────────────────────────────
fetch('/api/courses/enrolled', {
headers: { 'Authorization': `Bearer ${token}` }
});
// BACKEND — each step runs in order ────────────────────────
// 1. authMiddleware: identifies user from token
// 2. router: matches /api/courses/enrolled
// 3. controller: delegates to service
// 4. service: queries enrollments table for req.user.id
// 5. service: fetches course details for each enrollment
// 6. service: transforms and returns clean data array
// 7. controller: res.status(200).json(courses)
// BROWSER ───────────────────────────────────────────────────
.then(res => res.json())
.then(courses => renderCourseList(courses));6. Live Request Tracer
Trace GET /api/users/42/orders through 5 real Express files
Below is a real 5-file Express backend. Click ▶ Start Trace to walk through the request step by step — the active file and highlighted lines update automatically. You can also click any filename tab to read the code directly.
7. Debug the Request Flow
Five realistic failure scenarios — identify exactly where each breaks
Each scenario shows a request that fails somewhere in the backend lifecycle. Read the code, identify which layer the failure occurs in, and select the correct answer.
The client sends GET /api/user/42/orders but the route is /api/users/:userId/orders. What happens?
// Router has this route defined:
router.get('/api/users/:userId/orders', auth, controller.getOrders);
// ❌ Client sends:
// GET /api/user/42/orders
// ↑ missing 's'
// What does Express return?8. Mini Challenge — Trace a Course Enrollment
POST /api/courses/42/enroll — trace + find the intentional bug
Flow: Read → Trace → Identify Bug → Explain → Show Solution
9. Recap — The Backend Mental Model
Key terms and the complete request lifecycle in one view
CLIENT (browser / app) ↓ HTTP Request (method + URL + headers + body) SERVER ↓ WEB SERVER — receives TCP connection ↓ ROUTER — matches URL pattern ↓ MIDDLEWARE — auth, logging, rate limit, CORS ↓ CONTROLLER — validates, delegates ↓ SERVICE — business logic, rules, transforms ↓ DATABASE — SQL/NoSQL query executed ↑ Data returned up through all layers ↑ HTTP RESPONSE — status + headers + JSON CLIENT ← Renders data received from backend "The backend is the application layer that sits between clients and the data/services they need."