Phase 4 · Async, Data & ToolingModule 27~46 min read

HTTP, Fetch & REST APIs

Communicate with web services, handle failures, and build resilient data-loading flows.

What you'll learn

Fetch exposes HTTP as a promise-based primitive. Reliable clients separate transport failure, HTTP failure, data validation, cancellation, retries, and user-visible state.

By the end of this lesson, you'll be able to:

  • Send and parse HTTP requests
  • Distinguish network and HTTP errors
  • Design cancellation and safe retry behavior

Core mental model

Use this decision table as a compact reference. Focus on what each tool means and when it earns its place in production code.

ConceptWhat it meansDecision rule
Response statusHTTP outcome from the serverCheck response.ok before parsing success data
CORSBrowser-enforced cross-origin read policyConfigure the server; do not disable browser security
IdempotencyRepeating a request has the same intended effectRetry only safe or explicitly idempotent operations

Professional workflow

Build the behavior in small, observable steps. Each step should leave something you can inspect or test.

  1. Describe the HTTP request boundary: inputs, outputs, state, timing, and expected failures.
  2. Implement the smallest correct path with names that expose intent.
  3. Add edge cases and failure handling before introducing abstractions.
  4. Verify behavior with realistic data and one deliberately adversarial example.
  5. Refactor only after the observable behavior is protected.

Make behavior observable

Before optimizing or abstracting, make inputs, outputs, state changes, timing, and failure paths visible. JavaScript becomes much easier to reason about when hidden work is exposed.

Guided code lab

Create a typed failure boundary

Transport and HTTP failures become explicit caller-visible errors.

api-client.js
async function requestJson(url, options = {}) {
  const response = await fetch(url, options);
  if (!response.ok) {
    const message = await response.text();
    throw new Error("HTTP " + response.status + ": " + message);
  }
  return response.json();
}

POST JSON correctly

The request states its representation and serializes the body once.

create-note.js
const note = await requestJson("/api/notes", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ title: "Promises", complete: false }),
});
console.log(note.id);

Production practice

Contract

Document the HTTP request inputs, completion signal, failure channel, ordering, and cancellation behavior.

Verification

Test success, expected failure, timeout or cancellation, empty data, and out-of-order completion.

Operations

Expose duration and failure context without logging secrets or overwhelming the main thread.

Common failure mode

Fetch resolves normally for 404 and 500 responses; it rejects mainly for network and abort failures.

Independent workshop

Build an API client for course bookmarks with load, create, delete, timeout, and retry policy.

Your finished workshop must include:

  • Central response checking
  • AbortController timeout
  • No automatic retry of unsafe mutation

Definition of done

Demonstrate the happy path and at least two edge cases, keep responsibilities separated, and add a short note explaining one design choice.

Recap & quick check

Key takeaways

  • HTTP errors need explicit checks
  • Headers describe the body
  • CORS is a server/browser policy
  • Retries depend on request semantics

Quick check

1. Does fetch reject automatically for HTTP 404?

2. Who sends Access-Control-Allow-Origin?

3. Which method is normally safe to retry?

Keep the workshop. Later modules deliberately build on these decisions, so each exercise can become part of your final portfolio architecture.