JavaScript Curriculum
Talking to Servers
hardThe Nexus dashboard shows a live user profile loaded from a REST API. When the page opens, JavaScript fires a fetch request, waits for the response, checks the status, parses the JSON, and renders the data — all without a page reload. When the component unmounts, the request is cancelled. When the server returns a 404, the user sees a clear message. This is the complete pattern. Everything in Chapter 01 leads here.
The anatomy of an HTTP request
Every time your JavaScript code fetches data from a server, it sends an HTTP request — a structured message with four parts:
The method tells the server what you want to do. GET retrieves data. POST creates. PATCH updates partially. DELETE removes. These are conventions — REST conventions — that nearly every API follows.
The server replies with a response: a status code, headers, and a body.
fetch() — four stages
fetch() is the browser's built-in HTTP function. Watch exactly what happens at each stage, and how the outcome changes across three different server responses:
The most important thing to remember: fetch() only rejects on network failure. A 404 or 500 response resolves the Promise normally — with response.ok = false. You must check it manually.
The Response object
When fetch() resolves, you get a Response object. It contains everything the server sent back. Click each property to learn what it holds and how to read it:
const response = await fetch(url)
Click any property to see what it contains and how to use it.
The critical properties in every fetch call are response.ok and response.json():
Building the pattern — four levels
The same API call, written four ways — from dangerously naive to production-ready:
The simplest possible fetch. Works — until something goes wrong. No error checking, no loading state, no cleanup.
const response = await fetch('/api/users/42')
const user = await response.json()
console.log(user)
// If fetch fails → unhandled rejection
// If status 404 → user = { error: "Not found" } silently✗ Crashes silently on network errors, treats 404 as success, no way to cancel.
The production version introduces two things beyond error handling:
AbortController — lets you cancel an in-flight request. Essential in React: if a component fetches data and unmounts before the response arrives, the callback would try to update state on an unmounted component. Abort it in the cleanup function of useEffect.
Structured error objects — instead of throwing a plain string, attach status and code to the Error object so callers can handle different error types differently.
Sending data — POST and PATCH
Reading data is only half the picture. Sending data requires a body:
Key points: Content-Type: application/json tells the server how to parse the body. JSON.stringify() converts your object to a string — the body must be a string, not an object.
Query parameters and URL construction
Real APIs use query parameters for filtering, pagination, and search:
A complete data layer
In a real codebase, fetch calls are grouped into a data layer — functions that each own one API operation and handle all the plumbing internally:
Every component that needs user data calls usersApi.getById(id). The fetch mechanics are invisible to the component. When the API changes, you update one file.
Your challenge
loadProfile is a focused version of the pattern: fetch, check, parse, transform, return — or catch, log, return null. The ?? 0 on xp is optional chaining's partner: if the server doesn't include xp, default it to 0 rather than letting undefined silently propagate into the UI.
This is lesson-01 through lesson-13 applied. A real function, doing real work, with every edge case handled.
Challenge
Write an async function called loadProfile(userId) that fetches from '/api/users/' + userId. Check response.ok — if false, throw a new Error with 'User not found: ' + response.status. Parse the JSON body and return an object { name: data.name, role: data.role, xp: data.xp ?? 0 }. Wrap everything in try/catch — on error log 'loadProfile failed: ' + err.message and return null.
Talking to Servers
hardThe Nexus dashboard shows a live user profile loaded from a REST API. When the page opens, JavaScript fires a fetch request, waits for the response, checks the status, parses the JSON, and renders the data — all without a page reload. When the component unmounts, the request is cancelled. When the server returns a 404, the user sees a clear message. This is the complete pattern. Everything in Chapter 01 leads here.
The anatomy of an HTTP request
Every time your JavaScript code fetches data from a server, it sends an HTTP request — a structured message with four parts:
The method tells the server what you want to do. GET retrieves data. POST creates. PATCH updates partially. DELETE removes. These are conventions — REST conventions — that nearly every API follows.
The server replies with a response: a status code, headers, and a body.
fetch() — four stages
fetch() is the browser's built-in HTTP function. Watch exactly what happens at each stage, and how the outcome changes across three different server responses:
The most important thing to remember: fetch() only rejects on network failure. A 404 or 500 response resolves the Promise normally — with response.ok = false. You must check it manually.
The Response object
When fetch() resolves, you get a Response object. It contains everything the server sent back. Click each property to learn what it holds and how to read it:
const response = await fetch(url)
Click any property to see what it contains and how to use it.
The critical properties in every fetch call are response.ok and response.json():
Building the pattern — four levels
The same API call, written four ways — from dangerously naive to production-ready:
The simplest possible fetch. Works — until something goes wrong. No error checking, no loading state, no cleanup.
const response = await fetch('/api/users/42')
const user = await response.json()
console.log(user)
// If fetch fails → unhandled rejection
// If status 404 → user = { error: "Not found" } silently✗ Crashes silently on network errors, treats 404 as success, no way to cancel.
The production version introduces two things beyond error handling:
AbortController — lets you cancel an in-flight request. Essential in React: if a component fetches data and unmounts before the response arrives, the callback would try to update state on an unmounted component. Abort it in the cleanup function of useEffect.
Structured error objects — instead of throwing a plain string, attach status and code to the Error object so callers can handle different error types differently.
Sending data — POST and PATCH
Reading data is only half the picture. Sending data requires a body:
Key points: Content-Type: application/json tells the server how to parse the body. JSON.stringify() converts your object to a string — the body must be a string, not an object.
Query parameters and URL construction
Real APIs use query parameters for filtering, pagination, and search:
A complete data layer
In a real codebase, fetch calls are grouped into a data layer — functions that each own one API operation and handle all the plumbing internally:
Every component that needs user data calls usersApi.getById(id). The fetch mechanics are invisible to the component. When the API changes, you update one file.
Your challenge
loadProfile is a focused version of the pattern: fetch, check, parse, transform, return — or catch, log, return null. The ?? 0 on xp is optional chaining's partner: if the server doesn't include xp, default it to 0 rather than letting undefined silently propagate into the UI.
This is lesson-01 through lesson-13 applied. A real function, doing real work, with every edge case handled.
Challenge
Write an async function called loadProfile(userId) that fetches from '/api/users/' + userId. Check response.ok — if false, throw a new Error with 'User not found: ' + response.status. Parse the JSON body and return an object { name: data.name, role: data.role, xp: data.xp ?? 0 }. Wrap everything in try/catch — on error log 'loadProfile failed: ' + err.message and return null.