Requests
Identify method, path, headers and body.
CodeBhavyaTrace a request through trusted checks, business rules and a deliberate response.
The last lessons handled browser events, API responses and local preferences. This lesson follows the other end of the request: the application that decides what response to return. You will separate a browser interface from server-owned data, trace a handler pipeline and explain why a client-side check cannot protect a backend.
Our example is a small workshop service. Guests can read the catalog, recognized users can create bookings, and an administrator can inspect an aggregate report. The interactive lab simulates this pipeline locally so you can inspect every decision without needing a backend account.
Identify method, path, headers and body.
Select a handler and reject unsupported operations.
Validate input and apply identity, permission and capacity rules.
Return a deliberate status and representation.
Browser code controls the interface in the learner’s device. Server-side code executes in a backend environment and produces responses to requests. Both can use JavaScript, but they have different capabilities, inputs and trust boundaries. A filename ending in .js does not tell you where that code executes.
A server can work with private configuration and shared records that are not shipped to every browser. Browser scripts can read and change their own interface, and users can inspect or modify what that browser sends. Sending a secret inside frontend JavaScript does not make it private.
For the workshop example, the browser displays available places and collects a requested quantity. The backend must decide the current capacity and whether to create a booking. A learner cannot authorize a reservation by changing a displayed counter or sending an admin field.
Display a form and provide immediate feedback.
Carry the requested operation and input.
Check rules against trusted application state.
Return the result for the browser to display.
The lab intentionally puts both sides into one page for teaching. That makes its “server” inspectable and editable too. It demonstrates the order of checks; it cannot provide the protection of a separately deployed backend.
A static resource can be returned from a stored file, such as a course HTML page, image or stylesheet. A dynamic response is computed from request information and application state. A workshop catalog may be generated from current records even when its visual layout stays the same.
A dynamic application still serves static assets. Its HTML may reference ordinary CSS and JavaScript files. A static frontend can also call a separate dynamic API; server rendering is not required for every feature.
Consider two learners requesting their bookings. The route can be identical, but the recognized identity determines which records are returned. The response must be based on the correct user’s records rather than a browser-supplied user ID treated as authority.
A stylesheet can be served without constructing its contents per learner.
A handler can return a current list as JSON.
A server can render a page from a recognized user’s records.
Static assets and dynamic handlers can work together.
“Dynamic” describes how a response is produced, not whether the page has animations. A frontend animation can run entirely in the browser, while a visually plain page can be generated dynamically.
A request describes an operation. Its method conveys intended semantics, the path selects the target, headers carry metadata and the body can contain submitted data. Query parameters belong to the URL and need their own parsing and validation.
Our lab’s POST /bookings request uses a JSON body with exactly workshopId and seats. Content-Type identifies the supplied representation. An Authorization header carries a visibly fake fixture token so the local simulator can look up a predefined identity.
The preview shows what the simulator receives. GET handlers ignore the body controls; POST /bookings parses the body only after route, method and identity checks. This deliberate order is part of the exercise’s contract, not a requirement that all real frameworks have an identical middleware order.
POST /bookings HTTP/1.1
Content-Type: application/json
Authorization: Bearer fixture-learner
{"workshopId":"html","seats":1}This is an illustrative request, not a live endpoint or usable credential. A real client and backend must agree on their contract, transport and authentication mechanism. Do not paste real tokens into the teaching lab.
A router maps a method and path to a handler. Known paths may permit different methods. In our simulation, GET /workshops reads the catalog; GET /bookings reads the current identity’s bookings; POST /bookings attempts a new booking.
An unknown path returns 404. A known path with an unsupported method returns 405 and an Allow header listing the methods this simulation supports. DELETE /workshops is therefore different from GET /missing.
Do not treat a path as a filename or execute arbitrary code based on it. A framework normally offers explicit route declarations and parameter parsing. The simulator uses a fixed route map so you can see the decision without learning one framework’s syntax.
| Path | Supported methods | Rule |
|---|---|---|
| /workshops | GET | Public catalog, no mutation |
| /profile | GET | Recognized identity |
| /bookings | GET, POST | Own records or a validated booking |
| /admin/report | GET | Administrator only |
The toy router models only the listed methods. It does not implement a full web server’s handling of HEAD, OPTIONS, query strings, trailing slashes or URL decoding. A production router needs those decisions to be tested against its documented behavior.
GET is intended for reading a representation without requesting a state change. A request can still produce logs or other incidental effects, but a GET route should not book places merely because a learner follows its link.
POST asks a target to process supplied data according to its contract. In the lab, an accepted POST creates a booking. Repeating the same request creates another booking if capacity permits; this exercise does not implement deduplication or an idempotency key.
Do not assume that POST encrypts its body. HTTPS protects transport, while server validation and authorization decide what the operation may do. Keeping a value out of a query string does not make it trustworthy.
// Contract examples — not live calls from this page:
// GET /workshops -> read current catalog
// GET /bookings -> read this identity's bookings
// POST /bookings -> attempt to create a booking
// DELETE /workshops -> unsupported here: 405For a real create operation, decide what retries mean. Network failure can leave a client uncertain whether a write completed. A server-side idempotency strategy can make intended retries safe; merely disabling a browser button is insufficient.
A JSON parser checks text syntax and produces a value. It does not prove that the value contains the right fields or types. A valid JSON string, array or null is unacceptable for our booking object.
The exact lab contract is {workshopId, seats}. WorkshopId must be html, css or javascript. Seats must be a numeric integer from 1 to 3. Extra fields, including a client-supplied role or userId, are rejected. The accepted booking owner is derived from the recognized identity.
The body must be JSON and at most 2048 characters for this local exercise. In a deployed service, request-byte limits should also be enforced before an unbounded body is read or parsed. Browser maxlength and HTML validation improve feedback but can be bypassed.
const parsed = JSON.parse(rawBody);
// Check exact shape, allowed workshopId and integer seats.
const accepted = validateBooking(parsed);
// A loaded "1" string is not the required numeric 1.Our API chooses 400 for malformed JSON or invalid fields and 415 for an unsupported media type. Other APIs may use a different documented validation status. The important behavior is a clear rejection before changing records.
A handler often follows several stages: route selection, identity checks, parsing, validation, business rules, a data operation and response construction. Keeping these stages clear makes failures easier to explain and test.
The simulator first checks route and method. Protected routes then identify the caller. An admin-only handler checks its role. The booking handler checks media type, parses bounded text, validates the data, checks remaining places and finally commits one change.
An early rejection ends the pipeline. A request with an invalid identity never reaches the booking mutation. The trace records which stage accepted or rejected the request, and the response explains the outcome without showing internal stack traces.
Select POST /bookings.
Look up the fixture credential.
Validate the record and current capacity.
Create one booking, then return 201.
Real frameworks may place some checks in middleware shared by many handlers. Shared middleware reduces repetition, but you still need to know what data it validates and what trusted identity it supplies to a route.
A backend can render an HTML document using a template and records, or return JSON for a browser script to render. These are two representation choices. The same application may use both for different routes.
Templates separate a layout from values inserted into it. Use the template engine’s appropriate escaping behavior and avoid treating untrusted input as trusted markup. For a JSON API, validate the output contract and render values as text where HTML is not intended.
The lab returns JSON-shaped response objects. Its response panel is not an HTTP connection; it displays status, headers and body so you can inspect the contract. All displayed values use textContent.
// JSON response concept:
{
"id": "booking-1",
"workshopId": "html",
"seats": 1
}
// A template could instead place these values into an HTML page.A successful status and correct Content-Type should match the returned representation. Do not make a client guess whether a body is a JSON result or an HTML error page. The API loader in Level 18 already demonstrated why status checking and body parsing are separate stages.
A real workshop service needs shared, durable records. Two learners should not each receive a separate unlimited supply of places merely because they opened different browser tabs. A database or other server-owned store can provide the shared state.
Input validity and business validity differ. The number 2 can be a valid requested quantity, but a workshop with only one remaining place cannot accept it. Our lab returns 409 for that conflict and leaves its records unchanged.
The simulation begins with HTML: 3 places, CSS: 2 and JavaScript: 0. A successful booking decreases the selected remaining count and adds a booking. It is a synchronous memory exercise, so it does not demonstrate database durability or concurrent transactions.
// Illustrative SQL shape; bind parameters through the driver.
UPDATE workshops
SET remaining = remaining - :seats
WHERE id = :id AND remaining >= :seats;
// Check affected rows and insert the booking in one transaction.The statement is a design illustration, not a complete database program. In a real implementation, the capacity update and booking insert must succeed or roll back together, with an appropriate concurrency strategy. A browser counter and a separate check-then-write are not enough.
HTTP requests do not themselves carry an application’s remembered user object. An application may use an identifier to look up server-owned session state. That state can include a user ID, expiry and relevant authentication context.
A common browser flow uses a session cookie managed by the server. Other applications use explicitly supplied authorization tokens. These mechanisms have different security and lifecycle requirements. Session storage in the browser is not the server session and cannot establish an authenticated identity by itself.
Our lab uses public fake Bearer fixture tokens to select guest, learner, administrator or expired identity behavior. A predefined lookup supplies the mock user and role. There is no login, password, real cookie, secret credential or verified account in this page.
A request presents an identifier.
The backend validates it against its own rules.
A recognized user is available to the handler.
Expiry, logout and revocation need deliberate handling.
In a real service, identifiers must be created and protected appropriately, and sessions must expire or be invalidated when required. Do not copy the lab’s fixed strings into a production authentication system.
Authentication establishes who the caller is under the application’s rules. Authorization checks whether that caller may perform the requested operation on the target resource. A recognized learner is still not an administrator.
The simulator returns 401 with a Bearer challenge when a protected route lacks a recognized fixture. It returns 403 when the learner requests /admin/report. Public /workshops does not require an identity.
For GET /bookings, the response is filtered by the user ID obtained from the lookup. A request body cannot nominate a different owner. For POST, the record’s owner is assigned by the handler. This avoids making ownership depend on a client-editable field.
Recognize the credential through the trusted lookup.
Apply the route’s permission rule.
Use the recognized user when reading or creating records.
Stop before a data operation when a check fails.
Authorization belongs on the server at every protected operation. Hiding an admin button or disabling a control only changes the interface; it does not prevent a user from sending the request another way.
A status should describe the outcome, while the body gives enough information for the caller to respond. The simulator uses 200 for accepted reads and 201 for a newly created booking. A success message appears only after its mock commit.
Failure responses are deliberate: 400 invalid body, 401 unrecognized identity, 403 insufficient role, 404 unknown path, 405 unsupported method, 409 capacity conflict, 415 wrong media type and 500 the injected failure before commit. A failed request does not create a booking.
The server-failure switch affects only an otherwise acceptable POST booking and triggers before mutation. Invalid requests still fail at their earlier checks. This ordering helps learners separate a validation error from a backend operation failure.
| Try this | Expected status | State change |
|---|---|---|
| GET /workshops as guest | 200 | None |
| POST /bookings as guest | 401 | None |
| GET /admin/report as learner | 403 | None |
| Valid booking of an available place | 201 | One booking and reduced remaining count |
| Valid request for unavailable places | 409 | None |
A real server can log diagnostic details privately while returning a stable public error. Avoid leaking credentials, database statements or stack traces in responses. The trace in this teaching page is intentionally a visible explanation, not production logging.
Validate inputs on the backend, but also use defenses appropriate to where the data goes. Parameterized database queries keep values separate from query code. Output escaping or encoding depends on the destination context. Authorization checks keep records limited to permitted callers.
Cookie-authenticated state-changing requests need a deliberate cross-site request forgery strategy, such as the framework’s validated CSRF protection. SameSite cookie policy can contribute, but choosing POST alone is not a complete defense. The fixture lab does not model cross-site requests or implement production CSRF protection.
Keep secrets in backend configuration rather than public assets. Use HTTPS, resource limits, dependency maintenance and appropriate logging. Each protects a different part of the application; none turns a client-controlled role field into authority.
// Unsafe design idea:
// authorize(request.body.role === "admin");
// Better boundary:
// recognized = verifyCredential(request);
// requirePermission(recognized, "view-report");The commented names above describe responsibilities, not a ready-made security library. Use a framework’s documented facilities and test the entire application flow. The next language lessons can implement these concepts within their own runtime.
A backend needs an environment that can execute its language and accept requests. Uploading PHP or Python source beside static frontend files does not make a static file host execute it. The hosting setup must provide the matching runtime or a separately deployed service.
Configuration commonly includes service URLs, database access and secrets. Distinguish public settings needed by the browser from private values used only by the backend. A frontend repository should not become a delivery mechanism for database credentials.
Keep browser and backend changes connected through a documented API contract. A health response can confirm that a service answers a basic check, but it does not prove that booking validation, authentication or a database write works. Test those flows separately.
Execute the server language in a supported environment.
Keep private values in the backend’s protected settings.
Agree on routes, input, statuses and response fields.
Check real operations, errors and deployed behavior.
This lesson ships only frontend teaching files. It neither deploys an API nor adds a database. The local lab is useful preparation, and its request paths remain hypothetical until a real backend implements them.
Start with one complete flow rather than many unexplained endpoints. Define a catalog read and a booking create contract. Implement the server checks and data operation, then connect the browser with clear loading, success and failure states.
The browser should inspect status, parse the expected representation and validate what it displays. The backend should validate and authorize independently, even if the browser already rejects bad inputs. These complementary checks serve different responsibilities.
Test missing identity, a wrong role, malformed data, insufficient capacity and a failed write. For a durable system, also test retries and concurrent requests. A successful local simulation does not establish that a deployed runtime or database behaves correctly.
Collect the learner’s requested operation.
Validate and apply trusted rules.
Commit consistently or leave records unchanged.
Return and display a deliberate result.
The visualizer below follows an accepted booking. The interactive lab lets you interrupt the flow at different stages and inspect the unchanged or updated mock state. Next, PHP Fundamentals will introduce a concrete server language while preserving these boundaries.
Follow one accepted booking from request through route, identity, validation and a mock commit. The player uses the same approved five-stage presentation as the earlier lessons. The lab separately exposes the rejection paths.
A client requests one HTML place using the agreed JSON contract.
POST /bookings {"workshopId":"html","seats":1}This is a local teaching trace. A deployed backend would receive an actual HTTP request.
This is a local simulation, not a deployed API, login or real booking service. It sends no network requests and creates no cookies. All fixture identities and mock records are public teaching data in this page. Refresh or Reset simulator restores the starting state.
Choose a method, path and fake identity fixture. GET /workshops is public. Protected reads require a recognized identity; /admin/report requires the admin fixture. POST /bookings accepts exactly workshopId and numeric seats from 1 to 3. It assigns ownership from the fixture lookup, not the body.
Start with HTML: 3 places, CSS: 2 and JavaScript: 0. Successful bookings consume places; repeated accepted POSTs create additional bookings. The injected failure affects only an otherwise valid POST before commit. Inspect the request, staged trace, response and mock state after every action.
GET routes ignore this body. The booking contract accepts only workshopId and numeric seats. Use fictional data; never paste real credentials here.
Idle. No simulated request processed.
No request yet.No trace yet.No response yet.Starting places: HTML 3, CSS 2, JavaScript 0. No bookings.404 means unknown target here; 405 includes the supported methods.
Distinguish an unrecognized caller from a recognized caller without the required role.
Separate JSON syntax, record validation and capacity conflicts.
A failed operation must not consume places or create a partial booking.
If a guest POST returns 401 instead of 400 for bad JSON, inspect the trace: this handler checks identity before parsing. If a learner cannot open the report, signing in as that learner again does not supply the administrator permission.
If a valid request receives 409, read the current mock remaining count. Repeated successful POSTs have already consumed places. Reset restores the fixtures, but it also deliberately clears all bookings in this simulation.
If a failed request changes mock state, compare the mutation boundary with the rejected stage. A production database requires its own rollback and concurrency tests; the synchronous simulator does not establish those properties.
No. A caller can bypass browser checks. The backend must validate the received data and apply its own rules.
Static content can be served from stored resources; dynamic content is computed from request information and application state. A dynamic application can still serve static assets.
404 is an unknown path. 405 is a known path with an unsupported method and includes an Allow header.
It may be a valid input but exceed the current remaining places. Validation and capacity rules answer different questions.
Authentication recognizes the caller. Authorization decides whether that caller may perform the operation on the resource.
No. The handler derives ownership and permissions from the recognized identity, not client-supplied claims.
All its code, fixtures and state run in the browser and can be inspected or changed. It teaches a pipeline without implementing a separate server.
A consistent transaction and concurrency strategy so both succeed together or neither leaves a partial result. The local synchronous exercise does not test database guarantees.
Reset, then GET /workshops as guest. Expected: 200; remaining 3/2/0 and no bookings.
POST /bookings as guest with valid JSON. Expected: 401, Bearer challenge, no mutation.
GET /admin/report as learner, then as admin. Expected: 403 followed by 200.
Try GET /missing and DELETE /workshops. Expected: 404, then 405 with Allow: GET.
As learner POST /bookings with malformed JSON, seats "1" or an extra role. Expected: 400, no mutation; text/plain gives 415.
As learner POST HTML/2. Expected: 201; HTML remaining 1, one booking owned by user-1.
Request HTML/2 again: 409. Then request HTML/1 with server failure: 500. Expected: remaining stays 1.
GET /bookings as learner and admin. Expected: each sees its own records. Reset: all fixtures restored and mock bookings cleared.
The application environment that executes server-side logic and produces responses.
Content computed using request information and application state.
A mapping from a request target and allowed method to a handler.
Code that processes an accepted request and constructs its outcome.
Shared processing that runs around or before route-specific handler work.
Establishing the caller’s identity under the application’s rules.
Deciding whether a recognized caller may perform an operation on a resource.
Application state associated with a recognized request identity and its lifecycle.
A coordinated data operation that commits or rolls back related changes together.
A property where repeating an operation has the same intended effect as performing it once.
Write a contract for catalog reads, protected booking creation, own-booking reads and an administrator report. Specify methods, fields, body limits, identity requirements, permission checks and deliberate status codes. Separate browser feedback from backend enforcement.
Trace each lab scenario and state which check fails first. Keep malformed input, denied requests, capacity conflicts and a failed commit from changing records. Explain why ownership comes from trusted identity and why a repeated POST may need an idempotency design.
For a deployed implementation, select a runtime, protected configuration and shared data store. Use a suitable transaction for capacity and booking records, then test concurrent requests, retry behavior, sessions and real HTTP responses. Do not claim those guarantees from the browser simulation alone.
Success criterion: describe a complete request-to-response flow with clear boundaries and honest outcomes. Level 21 introduces PHP Fundamentals as a concrete server language.
Before marking complete, trace a successful booking and reproduce route, identity, permission, body, capacity and pre-commit failure outcomes. Explain how the real backend would differ from this teaching simulation. Completion is a local study marker, not a verified assessment.