Fetching Data and Browser APIs

Learn to load and send data with fetch, show the results on a web page and keep small amounts of data in the browser. You read HTTP requests, responses and JSON, handle loading and error states, and format dates and prices from an API for each reader. You find out why CORS errors happen and why secret API keys do not belong in front-end code, then use localStorage, sessionStorage and browser features such as geolocation and the clipboard.

BeginnerLesson 8 of 9 in JavaScript Programming Course

What you will learn

  1. Explain how an HTTP request and response work, load JSON data with fetch, and send data to an API with the right method, headers and body.
    • Read HTTP requests and responses
      Describe the parts of an HTTP request and response, match each HTTP method to the action it performs, and read status codes and headers in the browser's developer tools.
    • Load JSON data with fetch
      Call fetch, check the response status, read and parse the JSON body, and build request URLs with properly encoded query parameters.
    • Send data with POST, PUT, PATCH and DELETE
      Pass an options object to fetch to send JSON or form data, and handle the server's reply after creating, updating or deleting a record.
  2. Turn API results into page content, format dates and money for the reader, and keep the page clear while data loads, fails or arrives out of order.
    • Render API results into the page
      Build page elements from the arrays and objects in a JSON response, insert API text safely, and handle missing fields, empty results and paged results.
    • Format dates, numbers and money from API data
      Convert the date strings, timestamps and amounts that APIs send into readable text for the reader's language, region and time zone with the Intl formatters.
    • Show loading, error and empty states
      Track the stages of a request, show the user a clear message for each stage, and recover from failures with retries.
    • Cancel, time out and combine requests
      Abort requests that are no longer needed, set time limits, stop outdated responses from replacing newer ones, and run several requests in parallel or in sequence.
  3. Explain the same-origin policy and CORS errors, and protect API keys and user data when a page talks to other servers.
    • Understand the same-origin policy and CORS
      Identify the origin of a URL, explain why the browser blocks some cross-origin responses, and recognize how CORS headers and preflight requests let a server allow them.
    • Protect API keys and user data
      Explain what API keys and tokens do, why a secret in front-end code is public, and how to send credentials and handle user data responsibly.
  4. Save, read and update small amounts of data with localStorage and sessionStorage, and decide what is sensible and safe to keep in the browser.
    • Save and read data with localStorage and sessionStorage
      Use the Web Storage methods, explain how long each kind of storage lasts and who can read it, and convert numbers, booleans and objects to and from stored strings.
    • Use browser storage in an app
      Restore saved state when a page loads, cache API responses with an expiry time, keep tabs in sync, and decide what should not be stored.
  5. Detect and use browser APIs that need a secure page or the user's permission, such as geolocation and the clipboard, and give users a fallback when a feature is unavailable.
    • Get the user's location with the Geolocation API
      Check that a browser API is available, explain secure contexts and permission prompts, and use the Geolocation API with its options, errors and a fallback.
    • Copy text and use other browser APIs
      Copy text with the Clipboard API, react to connectivity changes, read parameters from the page address, and follow one method for learning any new browser API.

Fetching Data and Browser APIs study guide

5 chapters

1

Make requests and read the replies

A page can ask a server for data without loading a new page. The request says which resource you want and what you want to do with it; the response tells you what happened. You will follow that exchange in the Network tab, turn a JSON reply into JavaScript data, and send changes back to the server. The important checkpoints are the method, the status, and the shape of the body: a response arriving does not by itself mean the operation succeeded.

1.1 The parts of an HTTP exchange

A web API lets a program read or change data through named URLs called endpoints. JavaScript on the page is the client. It sends an HTTP request; the server answers with an HTTP response. Many APIs send JSON text, which can represent objects, arrays, strings, numbers, booleans and null.

Read a request

Consider GET https://api.example.com/books?author=Le%20Guin&limit=5. The method is GET, the path /books selects the resource, and the query string contains two parameters. The author value is "Le Guin"; %20 encodes the space. An ampersand separates parameters. The API documentation explains which parameter names it accepts and what each value means.

A request can also carry headers, which are name–value pairs, and a body, which holds submitted data. Accept: application/json asks for a JSON response. Content-Type: application/json describes the body being sent. Authorization carries credentials. Header names ignore letter case, so content-type and Content-Type identify the same header.

Choose the action
MethodIntended actionTypical use
GETReadGet a list of notes
POSTCreate or submitAdd a note
PUTReplaceSend the complete replacement note
PATCHChange partMark one note done
DELETERemoveDelete a note

GET and HEAD are safe methods: their intended purpose is reading, so do not use GET for a delete button. GET, PUT and DELETE are idempotent. Repeating the same request leaves the server in the same intended state as performing it once. Deleting an already deleted note can return a different status, but the note remains absent. Repeating a POST can create a second record.

Interpret the reply

The response contains a status code, headers and usually a body. The first digit groups the outcome:

  • 2xx: success. 200 OK commonly has data, 201 Created reports creation, and 204 No Content has no body.
  • 3xx: redirection. By default, fetch follows redirects.
  • 4xx: a problem with the request or access. 400 means bad request; 401 means missing or invalid credentials; 403 means the server understands but refuses the request; 404 means not found; 429 means too many requests.
  • 5xx: a server problem, such as 500 Internal Server Error or 503 Service Unavailable.

A call to /books/42 might return 200, a JSON content type and {"id":42,"title":"The Dispossessed","year":1974}. A call to /books/9999 might return 404 and {"error":"Book not found"}. Both calls received a response. A connection failure produces no HTTP status for JavaScript to inspect.

Inspect before guessing

Open developer tools, select Network, and trigger the action. Inspect the method, full URL, status, headers, body and timing. Compare them with the documentation's endpoint, required parameters, credentials, rate limits and example response. If the server returned the right data, investigate the page code; if the request URL is wrong, fix that before changing the renderer.

Key Takeaways

  • An endpoint is a URL that an API exposes for an operation.
  • The method selects the action; the URL selects the resource and parameters.
  • Request and response headers describe the exchange.
  • A 404 is a response, while a connection failure has no HTTP status.
  • Inspect the Network tab and compare the exchange with the API documentation.

1.2 Load JSON in two asynchronous steps

fetch(url) sends a GET request and returns a promise. Its result is a Response object, available when the headers arrive. Reading the body is a separate asynchronous operation. response.json() reads that body and parses it into JavaScript data.

Wait, check, read
async function loadBook(id) {
  const response = await fetch(`https://api.example.com/books/${id}`);
  if (!response.ok) {
    throw new Error(`HTTP error ${response.status}`);
  }
  return await response.json();
}

For loadBook(42), the first await gets the response. The condition rejects an unsuccessful HTTP outcome. The second await gets the parsed book, such as { id: 42, title: "The Dispossessed", year: 1974 }. The function itself returns a promise, so its caller also waits for the result.

response.ok is true for statuses from 200 through 299. An HTTP error such as 404 or 500 does not reject the fetch promise: a server answered. Network failure, a blocked CORS exchange, an invalid request URL or cancellation can reject it. Throwing on !response.ok lets a surrounding try/catch handle HTTP failures too.

Understand the body

Without await, const data = response.json() stores a promise, not the book. Accessing data.title then gives undefined. Leaving await off fetch similarly leaves a promise where the code expects a Response.

Choose the body reader for the response: json() for JSON, text() for text, or blob() for binary data. A body can be consumed only once. Store the parsed result and reuse it. To inspect raw JSON text as well, read text() once, then call JSON.parse(text) on that stored string.

Invalid JSON rejects with a SyntaxError. An HTML error page often causes an "Unexpected token '<'" message. An empty body, including a 204 reply, cannot be parsed as JSON either. Check the status first and inspect response.headers.get("Content-Type") when the format is in doubt. A success status alone does not promise a JSON body.

Build a query safely
const url = new URL("https://api.example.com/search");
url.searchParams.set("q", "rock & roll");
url.searchParams.set("limit", 10);

The resulting address is https://api.example.com/search?q=rock+%26+roll&limit=10. The embedded ampersand is encoded as part of the value. Gluing input onto "?q=" can give &, # or + their URL meanings and change the search. A relative URL follows normal address resolution: from https://notes.example.org/app/index.html, fetch("data/books.json") loads /app/data/books.json on that origin.

Follow the returned shape

For {"results":[{"title":"Dune"}],"total":1}, the first title is data.results[0].title. The outer object is not the results array. Use the response preview to find the array before looping.

A shared getJSON(url, options) helper can perform the same status check and body read for many calls. In a .then() chain, return response.json() from the response callback so the next callback receives parsed data. Attach .catch() at the end to handle rejected steps.

Key Takeaways

  • fetch and response.json() return separate promises.
  • Check response.ok; an HTTP error does not make fetch reject.
  • Read a response body once and reuse the stored value.
  • Use URL.searchParams to encode query values.
  • Read nested JSON according to its actual object and array structure.
  • A successful response can still contain an empty or invalid JSON body.

1.3 Send a change and use the server result

The second argument to fetch configures a request. Its options include method, headers, body, signal and credentials. Without these options, the request is a GET with no body. To submit JSON, you must prepare both its text and its content type.

Send JSON
const response = await fetch("https://api.example.com/notes", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ title: "Shopping", text: "Rice, lentils" }),
});

JSON.stringify produces {"title":"Shopping","text":"Rice, lentils"}. The header tells the server how to read that text. Passing the object directly as the body sends "[object Object]". Sending the JSON string without the header labels it text/plain;charset=UTF-8, which many JSON endpoints reject with 400 or 415 Unsupported Media Type.

A successful create often returns 201 with the stored record, such as {"id":17,"title":"Shopping","text":"Rice, lentils"}. Use this returned object to update the page: the server's new id is needed for later edits and deletion.

Replace or update
RequestBodyMeaning
PATCH /notes/17{"done":true}Change the supplied field
PUT /notes/17The complete replacement noteReplace the resource
DELETE /notes/17Often noneRemove the resource

A PUT body that omits a field can cause that field to be removed or reset, according to the API. Use the documented method for the intended change. PUT and PATCH may return an updated record with 200, or return 204 without a body.

Handle success without assuming that JSON always follows:

if (!response.ok) {
  throw new Error(`HTTP error ${response.status}`);
}
const saved = response.status === 204
  ? null
  : await response.json();

This pattern fits endpoints documented to return either JSON or 204. A delete can succeed and still produce a parse error if code blindly calls json() on its empty body.

Choose the body format

new FormData(formElement) collects named form fields and selected files. Pass it directly as body. Let the browser set Content-Type: multipart/form-data and its boundary; a manually supplied header can omit the boundary needed to separate the fields. A URLSearchParams body uses application/x-www-form-urlencoded.

GET and HEAD cannot carry a body through fetch. Put search terms and filters in the URL's query string. Attempting a GET with a body rejects with a TypeError before it can serve as a search request.

Finish safely after success or failure

Disable the submit button before awaiting a create request, then re-enable it in finally. A double click can otherwise send two POST requests and create two records. Do not automatically repeat an uncertain create operation: a lost reply does not establish whether the server made the change.

For an error status, the body may contain a useful message such as {"error":"title is required"}. Read it once if it is JSON; catch a failed parse and keep a general HTTP message for empty or HTML replies. Keep the user's entered text available so they can correct the request.

Key Takeaways

  • JSON requests need JSON.stringify and a matching content type.
  • Use PATCH for a partial change and PUT for a complete replacement.
  • Skip JSON parsing for 204 No Content.
  • Let the browser set the multipart header when sending FormData.
  • Use the server reply, including its assigned ID, to update the page.
  • Disable duplicate submissions and restore controls in finally.
2

Turn responses into a useful page

Fetching data is only the first part of an interface. Readers need useful results, readable dates and prices, and a clear message while they wait. You will build the display from the response shape, keep missing values from breaking it, and make success, empty results and failures visible. You will also control overlapping requests so a slow reply cannot replace newer results, and choose when independent requests can run together.

2.1 Build the display from data

Rendering turns an array or object into elements on the page. Keep the fetched data in a variable and give it to a rendering function. That separation lets you sort or filter the same data without asking the server for it again.

Create one element per item
function renderBooks(books, list) {
  list.replaceChildren();
  for (const book of books) {
    const item = document.createElement("li");
    item.textContent = `${book.title} (${book.year})`;
    list.append(item);
  }
}

For [{"title":"Kindred","year":1979},{"title":"Beloved","year":1987}], this creates two list items: "Kindred (1979)" and "Beloved (1987)". Clearing the container first makes a new search replace the previous search. Without that step, the old and new lists accumulate.

Keep external text as text

Use textContent for API titles, descriptions and other text. innerHTML parses a string as markup. A title containing <img src="x" onerror="alert(1)"> can then execute code. This is cross-site scripting, or XSS. Text from forms and storage needs the same treatment because it may also have come from an untrusted source.

Element properties set individual values, such as img.alt = book.title. They do not make every kind of value safe automatically. An API-supplied link still needs a protocol check:

try {
  const target = new URL(book.url, location.href);
  if (target.protocol === "https:" || target.protocol === "http:") {
    link.href = target.href;
  }
} catch {
  link.removeAttribute("href");
}

This code runs on a newly created link without an existing href. An invalid or disallowed URL leaves it without a destination. A javascript: URL is not ordinary web navigation. For images, provide meaningful alt text built from the data when possible.

Supply defaults without losing real values

Optional fields may be absent or null. book.author?.name ?? "Unknown author" first tries the nested name and then supplies a default. Optional chaining avoids accessing a property of a missing author.

The operator matters: 0 || "n/a" gives "n/a", while 0 ?? "n/a" keeps 0. The || operator replaces all falsy values, including zero and an empty string; ?? replaces only null and undefined. A book with zero available copies needs to display zero.

An empty results array is a successful search with no matches. Show "No books match your search." so readers can distinguish it from a page that has not loaded.

Replace a search, append another page

Many APIs return pages using page, limit, a total count or a next URL. With 47 results and 10 per page, four full pages hold 40 records and the fifth holds 7. A new search clears the previous list; "Load more" appends the next page to the current list. Keep those two display actions separate.

To sort a local copy newest first, use [...books].sort((a, b) => b.year - a.year) and render that copy. The spread creates a new array, so the saved response order remains available. Inspect the response shape before selecting the array: a paged API often puts it inside data.results.

Key Takeaways

  • Render from saved data so local sorting needs no new request.
  • Insert untrusted text with textContent.
  • Validate an API link’s protocol before assigning its destination.
  • Use ?. for missing nested data and ?? when zero must stay zero.
  • Replace results for a new search; append results for another page.

2.2 Format dates and amounts for people

APIs return values that are easy for programs to exchange. Readers need dates, times and amounts formatted for their language and region. Keep the stored value separate from the text used to display it.

Read the date format first

"2026-03-05T14:30:00Z" names one instant: 14:30 UTC on March 5, 2026. The Z means UTC. new Date(...) turns it into a JavaScript Date. A date-only string such as "2026-03-05" is interpreted as midnight UTC; a date and time without an offset, such as "2026-03-05T14:30", is interpreted as local time.

A Unix timestamp counts from January 1, 1970, UTC. APIs often count seconds, but Date takes milliseconds. new Date(1772721000 * 1000) gives the same March 5 instant. Omitting the multiplication gives a date in January 1970. Read the API documentation to identify the unit.

Pick a locale and time zone
const date = new Date("2026-03-05T14:30:00Z");
const dateFormat = new Intl.DateTimeFormat("en-US", {
  dateStyle: "medium",
  timeStyle: "short",
  timeZone: "UTC",
});
dateFormat.format(date);

The output is "Mar 5, 2026, 2:30 PM". With en-GB, it is "5 Mar 2026, 14:30". Using short dates produces "3/5/26" in en-US, "05/03/2026" in en-GB and "05.03.26" in de-DE.

The locale controls presentation; the time zone controls the local clock time. Without a timeZone, the formatter uses the device's zone. That instant is 9:30 AM in New York, 15:30 in Amsterdam and 11:30 PM in Tokyo. Keep and send instants in UTC and convert for display. A calendar date such as a birthday needs care: formatting midnight UTC in a zone west of UTC can show the previous day.

Keep currency separate from locale
const priceFormat = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "EUR",
});
priceFormat.format(1234.5);

This gives €1,234.50. For the same amount, de-DE with EUR gives 1.234,50 €; en-US with USD gives $1,234.50; en-US with JPY gives ¥1,235. JPY has no minor currency unit, so its normal display has no decimal places. Selecting a locale does not convert between currencies. Use the currency code supplied with the amount.

Some payment APIs send integer minor units. With USD, 1999 cents means 19.99 dollars: divide by 100 before formatting. Do not apply that divisor to JPY. Adding integer cents gives 1999 + 2550 = 4549, which formats as $45.49. This avoids the familiar decimal arithmetic result 0.1 + 0.2, which is 0.30000000000000004.

Reuse the formatter

Create a formatter once for a list. Use undefined as its locale to select the browser default; navigator.language reports the browser's preferred language tag. Other options format 0.256 as "26%", or 12.5 with unit "kilometer-per-hour" as "12.5 km/h". new Intl.RelativeTimeFormat("en", { numeric: "auto" }).format(-1, "day") gives "yesterday". Hand-built dates such as "03/05/2026" remain ambiguous across regions.

Key Takeaways

  • Check whether timestamps use seconds or milliseconds.
  • An explicit time zone makes date-time display predictable.
  • Locale controls formatting; currency comes from the data.
  • Convert documented minor units before formatting money.
  • Reuse Intl formatter objects across a list.
  • Date-only strings parse as UTC and can shift day when displayed in another zone.

2.3 Show what the request is doing

A request has a visible life cycle: idle, loading, then success or error. Success may contain data or an empty result. The page should explain each state so readers know whether to wait, change a search or try again.

Keep setup and cleanup together

In this handler, getJSON checks the HTTP status and parses the body, searchUrl builds the request URL, and renderResults updates the list. The button and status element already exist on the page.

async function search(query) {
  button.disabled = true;
  status.textContent = "Loading…";
  try {
    const data = await getJSON(searchUrl(query));
    renderResults(data.results);
    status.textContent = data.results.length === 0 ? "No results." : "";
  } catch (error) {
    status.textContent = "Could not load results. Check your connection and try again.";
    console.error(error);
  } finally {
    button.disabled = false;
  }
}

Setup happens before waiting. The success path renders results and handles an empty array. The catch replaces the loading message if any awaited step fails. finally restores the button after either path. If cleanup appeared only after a successful await, a failure would leave the control disabled.

Explain the useful cause

An HTTP error has a status to guide the message. For 404, say the item was not found. For 401, ask the user to sign in; for 403, explain that access is not allowed. For 429, ask them to wait. For 5xx, explain that the service has a problem and suggest trying later.

A TypeError from fetch can mean a network failure, a blocked CORS request or a bad URL. JavaScript does not get a reliable detailed CORS diagnosis; inspect the browser console and Network tab. A SyntaxError from json() points to invalid JSON. Cancellation and time limits produce errors such as AbortError and TimeoutError. Keep technical details in the console and give readers an action they can understand.

Make changes noticeable

Use an existing status element such as <p role="status"></p>. Its changes are announced to screen readers without moving focus. aria-live="polite" serves a similar purpose; role="alert" suits urgent errors. A spinner alone does not communicate an empty result or a failed request.

A Retry button calls the loading function again. Retrying unchanged 400 or 404 requests usually repeats the problem. Temporary network or service failures can justify a small, bounded retry sequence. Exponential backoff increases the pause, for example 1 second, 2 seconds, then 4 seconds. Respect a Retry-After response header; it may give a delay in seconds or an HTTP date. Avoid automatically retrying a create request that might already have succeeded.

If a refresh fails but earlier data is still useful, keep it visible with a note such as "Showing results from 10:42. Could not refresh." Do not silently make old results look current.

Test the difficult paths

Use developer tools to slow the connection, go offline, and request a missing path. Check that loading appears promptly, a failed request replaces it, an empty success has its own message, and controls become usable again.

Key Takeaways

  • Make loading, empty success, data success and errors visible.
  • Put shared cleanup in finally.
  • Give readers a useful action and keep technical details in the console.
  • Announce status updates through an appropriate live region.
  • Bound retries and respect the server’s requested delay.

2.4 Control overlapping and parallel requests

Requests can outlive the action that started them. A search reply may arrive after the reader has typed something else, and a slow service may leave a page waiting too long. Control which results are still relevant as well as whether each request succeeded.

Cancel work you no longer need

Create an AbortController, pass its signal to fetch, then call abort() to cancel the request. Cancellation can interrupt either the wait for headers or an ongoing body read. The rejection is normally named "AbortError".

const controller = new AbortController();
const response = await fetch(url, { signal: controller.signal });
// A cancel button can call controller.abort().
const data = await response.json();

Wrap both awaits in error handling. If your code cancels an outdated search on purpose, return quietly for that expected abort instead of telling the user that the service failed.

fetch has no built-in timeout option. Use a signal such as AbortSignal.timeout(5000) to limit the request to 5000 ms, or 5 seconds of active time. Before headers arrive it rejects with TimeoutError; after headers arrive, it can interrupt body reading.

Stop old searches from winning

A race condition occurs when completion order changes the result. A reader types "ca" and then "cat". If "ca" returns last and is rendered, the screen no longer matches the input.

One approach aborts the previous request before each new request. Another assigns each call a number and only lets the newest call update the page:

let latest = 0;
async function search(query) {
  const request = ++latest;
  try {
    const data = await getJSON(searchUrl(query));
    if (request !== latest) return;
    renderResults(data.results);
  } catch (error) {
    if (request !== latest) return;
    showError(error);
  }
}

The guard also prevents an old failure from replacing a newer success. Apply the same relevance check to loading messages and control cleanup when calls overlap.

Debouncing reduces how many calls begin. Clear the previous timer on each keystroke and start a new one, for example for 300 ms. Typing "paris" quickly then starts one request after the pause. Debouncing saves requests; it does not by itself prevent an earlier in-flight response from arriving late.

Decide what can run together

Independent requests can start together:

const [user, posts] = await Promise.all([
  getJSON(userUrl),
  getJSON(postsUrl),
]);

For durations of 300 ms and 500 ms, the pair takes about 500 ms instead of about 800 ms in sequence. Promise.all rejects as soon as one input rejects, but it does not cancel the other operations.

Use Promise.allSettled when partial results are useful. It waits for every input and reports each as { status: "fulfilled", value } or { status: "rejected", reason }. A dashboard can then show successful panels beside a failed one.

Dependent requests must stay in sequence. If a second URL needs an ID returned by the first request, wait for that ID before constructing the second request.

Key Takeaways

  • Pass an abort signal before calling abort().
  • Catch errors from both fetching and reading the body.
  • Ignore outdated results and outdated errors.
  • Debouncing reduces calls; a relevance check prevents stale updates.
  • Use Promise.all for independent work that must succeed together.
  • Use Promise.allSettled when partial results are useful.
  • Wait for prerequisite data before starting a dependent request.
3

Read cross-origin data and protect credentials

A request can look correct and still fail in a browser because the page and API belong to different origins. That boundary is controlled jointly by browser rules and the server’s response headers. You will identify the origin, interpret preflight and CORS failures, and distinguish permission to read a response from permission to perform an action. Credentials need a separate decision: anything delivered to a browser can be inspected by its user.

3.1 Understand the browser’s origin boundary

An origin combines a URL's scheme, host and port. A path is not part of it. https://shop.example.com/cart and /help on the same site share an origin. Changing to http://shop.example.com, https://api.example.com or https://shop.example.com:8443 changes the origin. HTTPS normally uses port 443.

Who allows the response to be read?

The same-origin policy limits which resources a page script can read. For a cross-origin fetch, CORS lets the API server grant access through response headers. A page at https://notes.example.org calling https://api.example.com/weather needs the API's permission to read the response.

Access-Control-Allow-Origin: https://notes.example.org grants that origin access. The value * permits any origin for a request without credentials. If the response has no matching permission, the browser hides it from the page and fetch rejects with a TypeError. The console gives the CORS diagnosis; JavaScript does not receive the detailed reason.

Adding Access-Control-Allow-Origin to the JavaScript request does not grant permission. It is a response header controlled by the server. Adding a custom request header can create an extra preflight check instead.

Why OPTIONS appears before POST

Some cross-origin requests need a preflight. The browser sends OPTIONS first, listing the intended method in Access-Control-Request-Method and non-safelisted header names in Access-Control-Request-Headers. The server permits them with Access-Control-Allow-Methods and Access-Control-Allow-Headers, along with the origin permission.

A basic GET, HEAD or POST with only allowed headers can avoid preflight. The permitted content types include text/plain, application/x-www-form-urlencoded and multipart/form-data. A JSON POST, an Authorization header, PUT or DELETE requires preflight unless a valid earlier permission is cached. If preflight is refused, the real request is not sent.

For a simple request, the real request can reach the server even when the browser later blocks reading its response. CORS therefore does not replace server authorization or input checking.

Cookies add another requirement

The default credentials: "same-origin" sends cookies only for same-origin requests. credentials: "include" allows eligible cookies on cross-origin requests too. Cookie SameSite rules and third-party-cookie policies still apply.

To let JavaScript read a credentialed response, the server must send Access-Control-Allow-Credentials: true and name the page's origin explicitly. Access-Control-Allow-Origin: * does not work with credentials. These headers do not force a browser to send an otherwise blocked cookie.

Diagnose without hiding the problem

mode: "no-cors" gives an opaque response with status 0 and no readable body or headers. It cannot provide JSON to a page. A request working in curl also does not establish browser CORS permission: terminal clients do not enforce that browser policy.

Inspect the console and Network tab. Check whether the preflight failed or the final response lacked permission. Fix the API's response configuration or route the call through your own server. During development, serve pages from a local server: file:// pages commonly have opaque origins. A local server still needs CORS permission when it calls a different origin.

Key Takeaways

  • An origin consists of scheme, host and port.
  • The server’s response headers grant cross-origin reading permission.
  • Preflight checks a proposed method and headers before the real request.
  • CORS can hide a response after a simple request has already been processed.
  • Credentialed responses require an explicit origin and a credentials header.
  • no-cors produces an opaque response, not readable JSON.

3.2 Keep secret keys off the page

An API key identifies a calling application for usage, limits and billing. An access token grants access for a user or session. Anyone holding a usable credential may be able to act under its authority, so decide where it belongs before adding it to a request.

Headers protect placement, not secrecy from the user

Providers may require Authorization: Bearer <token>, X-API-Key: <key> or a query parameter such as api_key. Follow the API documentation. A header avoids putting the credential into a full URL that can enter logs and analytics. An Authorization or custom header on a cross-origin call normally triggers preflight.

A header is still visible in developer tools. Visitors can inspect the JavaScript they download and the requests it sends. Minifying code or hiding a value behind a variable does not make it secret.

Follow the key through a weather request

Suppose browser code calls https://api.weather.example/v1/current?city=Lima&key=sk_live_4f9a2c. Anyone who opens Network can copy the key and use the account's quota. Moving that value into a build-time environment variable does not help if the build inserts it into the JavaScript delivered to the page.

A server-held secret changes the path:

  1. The page calls its own site at /api/weather?city=Lima.
  2. That site's server adds the secret and contacts the weather provider.
  3. The server returns the weather data to the page, keeping the secret out of the response.

The server still needs to control access and usage of its endpoint. Keeping the upstream secret on a server does not make unlimited public use harmless.

Some providers issue browser keys meant to be public. Apply the provider's domain restrictions, limit permitted APIs, and set usage quotas. Use a key this way only when its documented design allows it; a secret server key does not become a browser key by adding a domain restriction.

Respond to exposure

Keep credential files out of version control, for example by listing .env in .gitignore. This protects the file from being committed; it does not prevent a front-end build from publishing a value that the code embeds. If a key is exposed, revoke it and issue a replacement. Removing it from the newest commit leaves earlier history and any copies intact.

Protect the exchange and reduce waste

Use HTTPS for API calls so data and credentials are encrypted in transit. An HTTPS page's fetch to an HTTP API is blocked as mixed content. Encryption does not stop the person using the browser from seeing their own request.

A rate limit caps usage, for example at 60 requests per minute. Calls above the limit can return 429 Too Many Requests. Cache appropriate results, debounce search input and avoid duplicate calls. If the server supplies Retry-After, honor its delay instead of repeatedly retrying immediately.

Client-side validation makes forms easier to use, but anyone can call an endpoint without your form. The server must validate requests and authorize actions itself. When displaying its response, continue to treat strings as untrusted text and insert them with textContent.

Key Takeaways

  • Browser-delivered code and requests expose any credentials they contain.
  • A secret key belongs on the server that calls the provider.
  • Restrict public browser keys by domain, API and quota.
  • Revoke an exposed key; deleting it from current code is insufficient.
  • HTTPS encrypts transit, while the server still validates and authorizes requests.
4

Keep small amounts of state in the browser

A setting or draft can survive a reload without a new server request. Browser storage makes this convenient, but its values are strings and its lifetime depends on the store you choose. You will save and restore small pieces of state, validate old data before using it, and give cached API results an expiry time. You will also decide which data belongs elsewhere, since local storage is neither a secret vault nor the only safe copy of important work.

4.1 Save strings and restore their types

Web Storage offers two key–value stores: localStorage and sessionStorage. They use the same methods, so the main choice is how long the data should last and which tabs should share it.

Choose the lifetime
StoreLifetimeSharing
localStorageSurvives tab and browser closure until removed or clearedShared by pages of the same origin
sessionStorageSurvives reloads during the tab's page sessionSeparate for each tab and origin

Closing the tab ends its session storage. A newly opened page with an opener can start with a copy of the opener's session storage, but later changes remain separate. Avoid using session storage as a way to keep information secret from scripts.

Storage follows origins. https://app.example.com cannot share its store with http://app.example.com. Paths on the same origin do share it, so a prefix such as "notes-app:settings" helps keep multiple apps' keys distinct.

Use the storage methods
localStorage.setItem("notes-app:theme", "dark");
const theme = localStorage.getItem("notes-app:theme");
localStorage.removeItem("notes-app:theme");

setItem creates or overwrites an entry. getItem returns its string value or null if it is absent. removeItem removes one entry. clear() removes all entries from that storage area for the origin, which can affect other features on the same site. length and key(index) let you inspect the keys.

Use these methods instead of property assignments such as localStorage.theme = "dark". Keys such as "length" or "key" can collide with built-in members when accessed as properties.

Convert values deliberately

After localStorage.setItem("count", 5), reading gives "5". Adding 1 directly creates "51". Number(localStorage.getItem("count")) + 1 produces 6.

A stored boolean has a similar trap. setItem("darkMode", false) stores "false", and a nonempty string is truthy. Read with localStorage.getItem("darkMode") === "true" when those are the two expected stored strings.

Objects and arrays need JSON:

localStorage.setItem("settings", JSON.stringify({
  theme: "dark",
  fontSize: 18,
}));
const settings = JSON.parse(localStorage.getItem("settings"))
  ?? { theme: "light", fontSize: 16 };

Without serialization, an ordinary object becomes "[object Object]". JSON.parse(null) gives null, so the default covers a missing entry. A malformed stored string still needs try/catch, and parsed data needs a shape check before use.

Keep the workload small

Web Storage calls are synchronous: JavaScript waits for each one on the main thread. Use it for settings, a draft or a short list, not large collections or files. IndexedDB provides asynchronous storage for larger structured data.

Current browsers commonly allow about 5 MiB in each Web Storage area per origin. A full store can make setItem throw QuotaExceededError; access may also fail under browser privacy settings. Handle failure without preventing the rest of the app from working. Developer tools expose the stores in Chrome and Edge's Application tab or Firefox's Storage tab, where deleting entries helps test first visits.

Key Takeaways

  • Choose localStorage for persistent shared settings and sessionStorage for tab-session state.
  • Storage areas are separated by origin.
  • getItem returns a string or null.
  • Serialize objects with JSON and restore their types on reading.
  • Handle storage failures and keep synchronous writes small.

4.2 Restore state and expire cached data

An app usually loads on start and saves on change. Read a saved list when the page opens, render it, and save the updated list after an edit. Browser storage is a convenience copy: it can be missing, damaged, outdated or cleared.

Validate before restoring

This loader expects a saved array of strings:

function loadTodos() {
  try {
    const value = JSON.parse(localStorage.getItem("todos"));
    if (Array.isArray(value) && value.every(item => typeof item === "string")) {
      return value;
    }
  } catch {
    // Continue with an empty list if reading or parsing fails.
  }
  return [];
}

JSON.parse alone does not prove the value is an array or that its items fit the app. Valid JSON such as 42 still has the wrong shape. A versioned value such as { version: 2, todos: [...] } lets newer code recognize older formats and either convert them or restore a default.

Save the in-memory list with localStorage.setItem("todos", JSON.stringify(todos)) after each change. Catch write failures too; a page should be able to keep working even when it cannot preserve the next reload's state. A form draft that belongs only to one visit can use sessionStorage.

Give cached responses a timestamp
localStorage.setItem("weather", JSON.stringify({
  savedAt: Date.now(),
  data,
}));

On a later load, first validate the cached object's shape and timestamp. Its age is Date.now() - savedAt. Use it only while that age is less than 10 * 60 * 1000, or 600,000 ms. A value saved at 10:00:00 is 450,000 ms old at 10:07:30 and can be used. At 10:12:00, it is 720,000 ms old, so fetch a fresh value. At exactly 600,000 ms it is expired under this rule.

Expiry is app logic: localStorage does not delete an entry when your freshness interval ends. Reject a missing or invalid timestamp instead of treating an unknown age as fresh. You can keep stale data visible during a failed refresh if it is labeled as old.

Sync other tabs

When one tab changes localStorage, other same-origin tabs receive a storage event. The writing tab does not receive its own event. The event exposes key, oldValue, newValue and url.

window.addEventListener("storage", (event) => {
  if (event.key === "theme") applyTheme(event.newValue);
});

Apply the theme immediately in the writing tab too. Handle null when a key is removed. A storage event is not a replacement for updating your own page's state.

Decide what belongs elsewhere

Do not put passwords, payment card numbers or secret API keys in Web Storage. Scripts on the origin can read it, including third-party code and injected scripts. Clear relevant personal data at sign-out on shared devices. Keep important work on a server or provide export because users can clear site data and private sessions discard it.

Cookies differ: matching requests send them to the server, and HttpOnly cookies cannot be read by page scripts. They are small, about 4 KB each. Web Storage stays in the browser and is script-readable. IndexedDB fits larger structured data through an asynchronous API.

Key Takeaways

  • Validate parsed data and fall back when it is missing or damaged.
  • Cache freshness comes from a timestamp and an app-defined age limit.
  • The storage event reaches other same-origin tabs, not the writer.
  • Keep secrets and irreplaceable data out of Web Storage.
5

Use location and clipboard features

Browser APIs connect a page to capabilities such as location and the clipboard. Their availability depends on the browser, the page’s security context and the user’s choices. You will detect a feature before calling it, ask for permission at a useful moment, and handle success or refusal. A complete interaction includes visible feedback and another way to finish the task, such as entering a city or copying selected text with the keyboard.

5.1 Request a location with a fallback

Geolocation is a browser API: a capability provided by the browser, separate from the JavaScript language. Like other device features, it can be unavailable or refused. A weather page should still work when a reader chooses to type a city.

Check the feature and the context

Detect the capability itself with "geolocation" in navigator. Checking a browser's name is less reliable: versions and settings change what is available. Geolocation needs a secure context, normally HTTPS; http://localhost also qualifies for development. window.isSecureContext reports whether the current page qualifies. Plain HTTP on another device's network address is not the same as localhost.

Explain why location is useful and request it when the reader clicks "Use my location". The browser manages the permission prompt. A person can allow or block it, and an earlier denial can cause a later call to fail without another prompt. Site settings are where the user changes that decision.

Read the callback result

navigator.geolocation.getCurrentPosition(success, error, options) uses callbacks. On success, position.coords contains latitude and longitude in decimal degrees and accuracy in meters. Accuracy is an estimated uncertainty radius, not extra decimal precision. On failure, code 1 means permission denied, 2 means position unavailable, and 3 means timeout.

The options control the attempt:

  • enableHighAccuracy: requests higher accuracy; default false.
  • timeout: waiting limit in milliseconds; default Infinity.
  • maximumAge: maximum age of an acceptable cached position; default 0.

Use a finite timeout so the page has a path out of waiting. watchPosition observes updates over time and returns an ID; pass that ID to clearWatch when tracking should stop.

Wrap callbacks when using await
function getPosition(options) {
  return new Promise((resolve, reject) => {
    navigator.geolocation.getCurrentPosition(resolve, reject, options);
  });
}

async function useLocation() {
  if (!("geolocation" in navigator)) {
    showCityInput();
    return;
  }
  try {
    const { coords } = await getPosition({ timeout: 10000 });
    const url = new URL("https://api.example.com/weather");
    url.searchParams.set("lat", coords.latitude.toFixed(2));
    url.searchParams.set("lon", coords.longitude.toFixed(2));
    await loadWeather(url);
  } catch {
    showCityInput();
  }
}

Here showCityInput displays the manual entry control and loadWeather requests and renders weather. Connect useLocation to the location button. The catch covers location failure and the weather request; either way, manual entry remains available.

Request only useful precision

A position of latitude 52.3676, longitude 4.9041 with accuracy 35 has an estimated radius of about 35 m. Rounding to 52.37 and 4.90 reduces the precision sent to the weather service. A latitude interval of 0.01° is about 1.1 km; longitude spacing varies with latitude. That regional precision suits a forecast without sharing the most detailed coordinates.

Where the Permissions API is available, navigator.permissions.query({ name: "geolocation" }) reports "granted", "denied" or "prompt". Detect and handle that API too. Its state helps tailor the interface but does not replace error handling for the location call.

Key Takeaways

  • Detect Geolocation and use a secure context.
  • Request location after a clear user action with a stated purpose.
  • Latitude and longitude use degrees; accuracy uses meters.
  • Set a finite timeout and offer manual entry on failure.
  • Send only the location precision the feature needs.
  • Permission state does not guarantee a usable position.

5.2 Copy text and learn another browser API

The Clipboard API lets a page copy text without asking the reader to select it first. Like Geolocation, it needs capability checks, an appropriate user action, error handling and a fallback.

Copy during the click

navigator.clipboard.writeText(text) returns a promise. Wait for it before reporting success. A secure context is required, and a denied operation can reject with NotAllowedError. Call it directly from a click handler: Firefox and Safari require a recent user interaction, while Chromium's requirements can also depend on clipboard-write permission.

copyButton.addEventListener("click", async () => {
  try {
    if (!navigator.clipboard?.writeText) {
      throw new Error("Copy unavailable");
    }
    await navigator.clipboard.writeText(codeField.value);
    copyButton.textContent = "Copied!";
  } catch {
    codeField.focus();
    codeField.select();
    copyButton.textContent = "Copy selected text: Ctrl+C / Cmd+C";
  }
  setTimeout(() => {
    copyButton.textContent = "Copy";
  }, 2000);
});

codeField is a text input or textarea and copyButton is the page's button. If copying fails, selecting the text gives a keyboard route: Ctrl+C on many systems or Cmd+C on macOS. The label returns to "Copy" after 2000 ms. Never show "Copied!" before the promise fulfills.

Reading uses navigator.clipboard.readText() and has tighter controls because a clipboard can contain private material from other apps. A browser can require permission or present a paste prompt. Permission to write does not establish permission to read.

Treat connectivity as a hint

navigator.onLine and the window's online and offline events help show a connection banner. They do not establish whether your API is reachable. A device can have a network connection while the API server is down or inaccessible.

window.addEventListener("offline", () => {
  status.textContent = "You are offline.";
});

Continue to handle errors around fetch even when navigator.onLine is true. Use an appropriate live region for the status message.

Read a shareable search

The URL API reads the page's own query string as well as building API URLs. On https://books.example.org/search?q=dune, new URL(location.href).searchParams.get("q") returns "dune". Read that value on load to restore a search from a shared link. A missing parameter returns null, so decide what the initial screen should show then.

Use one learning method

For another browser API, read its syntax, secure-context and permission rules, compatibility table, and MDN Baseline status. Then detect the feature, call it from a user action when required, handle its promise or callbacks, and provide an alternative when it is missing or refused.

The Notifications API displays system notifications after permission; Web Share opens a device share menu where supported; Canvas draws graphics; media APIs control audio and video. A third-party mapping API may add a library and a provider key. Its credentials follow the same secret-key rules as any other service. Testing one browser over localhost does not establish that another device or browser has the same support and context.

Key Takeaways

  • Wait for writeText before reporting a successful copy.
  • Keep a keyboard-copy fallback when clipboard access fails.
  • Clipboard reading has separate, tighter permission rules.
  • Online status does not establish API reachability.
  • Use URL parameters to restore a shareable search.
  • Check compatibility, detect features and handle refusal for each browser API.

Fetching Data and Browser APIs examples

5 Walkthroughs

1

Build and update a reading list

14 steps
Follow a request from its URL through its JSON reply, then submit a new record and handle the server’s result.
  1. 1
    IntroductionFollow one exchange

    A reading-list page needs to load books and add a note about one of them. The page is the client; the API is the server. Each exchange has a request describing the action and a response describing its outcome.

    We will read the exchange first, then connect the two asynchronous steps in JSON loading, and finally submit a change. The server’s reply determines what the page can safely show next.

  2. 2
    ExampleRead the resource and filters

    The page requests GET https://api.example.com/books?author=Le%20Guin&limit=5.

    GET asks to read. /books names the resource. The query filters by author and limits the result count. %20 represents the space in "Le Guin". The API documentation determines these parameter names; the page cannot choose a different name and expect the service to understand it.

  3. 3
    Key InsightSeparate status from connection

    A response can report 200 OK with a book or 404 Not Found with an error. Both prove that a server answered. A connection failure supplies no HTTP status to the page.

    Inspect the Network tab for the full URL, method, status, headers and body. If the API returned the expected JSON, the next place to inspect is the code that reads or displays it.

  4. 4
    ChallengeChoose a method for a change

    A note already exists. The page should change only its done field while preserving its text. Which HTTP method fits that operation, and why would GET be wrong?

    ---reveal---

    Use PATCH for the partial update. GET is a safe read method and must not be used to request a data change. PUT would describe a complete replacement and could reset fields omitted from the body.

  5. 5
    ExplanationWait for the response

    Start with const response = await fetch(url). This waits until the response headers arrive and gives a Response, not the parsed books.

    The reply may still be an HTTP error. fetch fulfills for a 404 because a response exists. Check response.ok before treating the operation as successful; it is true for status codes 200 through 299.

  6. 6
    ExampleCheck and read the body

    Continue inside the async function:

    if (!response.ok) {
      throw new Error(`HTTP error ${response.status}`);
    }
    const data = await response.json();
    

    The second wait reads and parses the body. Now data is a JavaScript value. An outer try/catch can handle both the status error thrown here and failures from fetching or parsing the body.

  7. 7
    ExampleFind the nested array

    Suppose the body is {"results":[{"title":"Dune"}],"total":1}.

    The first step, data.results, reaches the array. [0] reaches its first object. .title gives "Dune". A renderer should receive data.results, not the whole outer object. The Network response preview is useful when the API’s shape differs from what the page expected.

  8. 8
    ChallengeDiagnose the missing value

    The code uses const data = response.json() and then tries data.results[0]. The body really is valid JSON with a results array. What is missing?

    ---reveal---

    Wait for the body: const data = await response.json(). Without that wait, data is a promise and has no results property. The first await fetch(...) did not also wait for JSON parsing.

  9. 9
    TipPreserve punctuation in a search

    Build query parameters through the URL API:

    const url = new URL("https://api.example.com/search");
    url.searchParams.set("q", "rock & roll");
    

    The value becomes rock+%26+roll. The ampersand stays inside the search phrase instead of splitting the query. Reuse the parsed response after loading: calling a second body reader on the same response fails because the body was consumed.

  10. 10
    ExamplePrepare a JSON submission

    To create a note, serialize the fields and name their format:

    const response = await fetch("https://api.example.com/notes", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ title: "Read", done: false }),
    });
    

    The method requests creation, the header declares JSON, and the body contains JSON text rather than an ordinary object.

  11. 11
    ConnectionUse the stored record

    The server may return 201 Created with {"id":31,"title":"Read","done":false}. Add that returned record to the page’s state. Its ID lets a later action call /notes/31.

    For a form with files, pass FormData instead of JSON and let the browser set its multipart boundary. A GET request cannot carry a body through fetch; search fields belong in the query string.

  12. 12
    ChallengeHandle a bodyless success

    Deleting a saved note returns 204. The code checks response.ok, then calls response.json() and shows an error. Did deletion necessarily fail, and what should change?

    ---reveal---

    No: 204 reports successful completion without a body. Skip JSON parsing for that status and update the page after the status check. The parse failure came from trying to read empty content, not from evidence that the delete failed.

  13. 13
    ChallengeReview a complete submit flow

    A save button can be clicked twice while a POST runs. A successful reply supplies a new ID. Name the two page behaviors that prevent an accidental duplicate and preserve that ID.

    ---reveal---

    Disable the button during the request and restore it in finally. On success, update from the returned record, including its ID. The button prevents repeated clicks; the server result supplies values that did not exist in the submitted data.

  14. 14
    RecapCheck the exchange at each boundary

    When a request misbehaves, inspect the operation in order: the documented URL and method, the actual status, the chosen body reader, and the data shape handed to the page.

    For a write, check the content type and serialized body too. A success without content needs no JSON reader. A create reply should supply the saved record used for the next edit or delete.

2

Build a search page that stays current

18 steps
Render a list, format a price and date, and keep request state correct during slow, failed and overlapping searches.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionKeep the screen tied to the search
  2. 2
    ExampleReplace the previous list
  3. 3
    Key InsightKeep zero and missing data distinct
  4. 4
    ChallengeHandle external text and links
  5. 5
    ExampleRead the time unit
  6. 6
    ExplanationChoose the display zone
  7. 7
    ExampleFormat documented minor units
  8. 8
    ChallengeSeparate locale from value
  9. 9
    ExplanationBegin with visible waiting
  10. 10
    ExampleFinish all paths
  11. 11
    ChallengeRecognize a successful empty search
  12. 12
    TipWait before a temporary retry
  13. 13
    ExampleNotice the completion order
  14. 14
    ExampleCancel an outdated request
  15. 15
    ConnectionReduce calls during typing
  16. 16
    ChallengeChoose partial success
  17. 17
    ChallengeProtect the whole current interaction
  18. 18
    RecapTest the interface with imperfect responses
3

Diagnose a cross-origin API call

10 steps
Trace browser reading permission separately from server authorization and the protection of a provider key.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionSeparate two permission questions
  2. 2
    ExampleCompare the full origins
  3. 3
    ExplanationRead the server’s permission
  4. 4
    ExampleFollow the preflight first
  5. 5
    ChallengeExplain a terminal-only success
  6. 6
    ExampleFind the exposed key
  7. 7
    ConnectionMove the secret’s boundary
  8. 8
    ChallengeDistinguish transport from secrecy
  9. 9
    ChallengeCheck cookies and readable replies
  10. 10
    RecapDiagnose the boundary that failed
4

Restore a saved list without breaking the page

12 steps
Choose storage lifetime, preserve data types, validate restored data and apply a cache freshness rule.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionKeep a convenient local copy
  2. 2
    ExplanationChoose what should survive
  3. 3
    ExamplePreserve an array as text
  4. 4
    ChallengeRestore the intended type
  5. 5
    TipHandle a write that cannot fit
  6. 6
    ExampleCheck more than JSON syntax
  7. 7
    ExampleAttach a cache time
  8. 8
    ChallengeCalculate which cache is fresh
  9. 9
    ConnectionFollow a theme across tabs
  10. 10
    Key InsightProtect important data
  11. 11
    ChallengeRecover from an old saved format
  12. 12
    RecapTest a fresh and a returning visit
5

Add useful location and copy buttons

13 steps
Build permission-aware interactions with feature detection, clear feedback and manual alternatives.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionMake the action understandable
  2. 2
    ExplanationCheck the context and capability
  3. 3
    TipAsk when the feature is useful
  4. 4
    ExampleSet a finite wait
  5. 5
    ExampleRead only useful precision
  6. 6
    ChallengeRecover from a refusal
  7. 7
    ExampleWrite during the click
  8. 8
    Key InsightWait before celebrating the copy
  9. 9
    ChallengeTreat a connection signal as a hint
  10. 10
    ConnectionRestore a search from its link
  11. 11
    TipCheck another browser feature
  12. 12
    ChallengeReview both buttons together
  13. 13
    RecapTest the person’s choices too

Fetching Data and Browser APIs practice questions

40 Practice Questions in 4 sets

Set 1: Debug requests, storage and permissions10 Practice Questions

Question 1 of 10

A saved boolean is restored with if (localStorage.getItem("compact")). The stored text is "false", yet compact mode turns on. Why?
  1. Web Storage restores boolean values using their original types.
  2. A missing storage key returns the string "true" by default.
  3. A nonempty string is truthy, even when its text is "false".
  4. The if statement changes the stored text into a true value.
Show answerHide answer
Answer: C
getItem returns text, and the nonempty string "false" is truthy in JavaScript. It does not automatically become the boolean false again. If the stored format is "true" or "false", compare the value explicitly with "true" when restoring the setting.

Question 2 of 10

A service documents PUT /profiles/29 as replacing the profile. What does idempotence imply when the same complete request is sent twice?
  1. The two responses must contain exactly the same status and headers.
  2. The second request must be rejected before reaching the service.
  3. The server must create a new profile for each identical request.
  4. The intended stored profile is the same as after one request.
Show answerHide answer
Answer: D
Idempotence concerns the intended effect on server state, so repeating this replacement leaves the same profile as one replacement. It does not promise identical responses or prevent the second request from reaching the server. Creating a separate record on every repetition would not match the documented replacement action.

Question 3 of 10

A create request times out after the server may have received it. The page retries immediately, renders only the submitted fields, then sends an edit to an undefined ID. What design should replace this sequence?
  1. Prevent repeats, resolve uncertain creates, and retain returned IDs.
  2. Retry timeouts, keep submitted fields, and derive IDs from list order.
  3. Prevent clicks, retry each timeout, and retain only submitted fields.
  4. Allow repeats, discard returned IDs, and use the create URL for edits.
Show answerHide answer
Answer: A
A timed-out POST may already have created a record, so prevent duplicates and resolve that outcome before repeating it. Once creation is confirmed, keep the server’s returned ID for later edits. Disabling double clicks alone does not make a timeout safe to retry, and submitted fields cannot supply a new server ID.

Question 4 of 10

An event API documents its timestamp in seconds. A page passes it directly to new Date and shows January 1970. What conversion should precede date formatting?
  1. Divide the timestamp by 1000.
  2. Add the reader’s UTC offset.
  3. Multiply the timestamp by 1000.
  4. Replace the formatter’s locale.
Show answerHide answer
Answer: C
The API counts seconds but JavaScript Date counts milliseconds, so multiply the documented value by 1000. A locale controls how a date is written and cannot repair the wrong time unit. Adding a zone offset also does not correct a timestamp that is smaller by a factor of 1000.

Question 5 of 10

A catalog retains yesterday’s data after a refresh returns 503 with Retry-After: 12. What behavior communicates the state and supports recovery?
  1. Hide the failure and keep the old data labeled as updated just now.
  2. Label the data as old and wait at least 12 seconds before a bounded retry.
  3. Clear the list and immediately repeat until a success status arrives.
  4. Treat the response as empty success and disable all future refreshes.
Show answerHide answer
Answer: B
The older data can remain useful if the page clearly labels it as stale and explains that refresh failed. Retry-After: 12 asks for a twelve-second delay before another attempt; retrying immediately ignores that instruction. A 503 is a service failure, not evidence that the catalog contains no items.

Question 6 of 10

An account view needs a profile and its team label. The profile returns teamId. Notices are independent and may fail without hiding account data. How should the work be arranged?
  1. Start every request together, then reject the whole view on any failure.
  2. Run a profile-to-team chain beside notices; handle each branch’s outcome.
  3. Wait for notices, profile and team in sequence, sharing one error handler.
  4. Start notices after the profile; start the team only if notices also succeed.
Show answerHide answer
Answer: B
The team request depends on the profile’s ID, so those two form a sequence. Notices can run independently beside that sequence, with separate outcomes so their failure does not hide account data. Starting every request together lacks the team ID, while making notices a prerequisite adds an unrelated dependency.

Question 7 of 10

A provider’s secret key was committed to a repository. What action addresses use of the exposed credential?
  1. Remove it from the newest commit only.
  2. Rename it in the JavaScript source.
  3. Move it into a public request header.
  4. Revoke it and issue a replacement.
Show answerHide answer
Answer: D
Revoke the exposed credential so copied versions stop authorizing new requests, then create a replacement and store it appropriately. Removing the key from current code does not remove repository history or copies already made. Renaming a variable or changing a request field does not invalidate the key.

Question 8 of 10

Two same-origin tabs share compact mode as the strings "true" or "false". Tab A saves "false" but waits for its own storage event; tab B handles the event with Boolean(event.newValue). Removing the key should turn compact mode off. What update rule handles all three cases?
  1. Apply changes in the writer and listeners; enable only for the string "true".
  2. Rely on events in both tabs; enable for every nonempty stored string.
  3. Apply changes in the writer only; retain the previous mode in other tabs.
  4. Reload the writer; use Boolean on event values and retain mode after removal.
Show answerHide answer
Answer: A
The writing tab must update directly because it receives no storage event for its own change. Other tabs handle the event, and comparing the value with "true" keeps both "false" and null in the off state. Boolean conversion would incorrectly enable compact mode for the nonempty string "false".

Question 9 of 10

A location result has latitude -12.0464, longitude -77.0428 and accuracy 80. What does 80 describe?
  1. A position estimate at 80 meters above sea level.
  2. An 80 percent chance that the location is exact.
  3. A guarantee that the device lies within 80 meters.
  4. An estimated horizontal uncertainty radius of 80 meters.
Show answerHide answer
Answer: D
Accuracy describes the estimated uncertainty of the horizontal position in meters. It is not another coordinate, a timestamp or a guaranteed exact distance from the reported point. The latitude and longitude give the estimated position; the accuracy value describes how tightly that estimate is expected to locate the device.

Question 10 of 10

A page at https://recipes.example.org/search?q=green+tea reads new URL(location.href).searchParams.get("q"). What value does it get?
  1. "green+tea"
  2. "q=green+tea"
  3. "green tea"
  4. null
Show answerHide answer
Answer: C
searchParams.get("q") retrieves and decodes the value of the named query parameter, so the plus becomes a space in "green tea". It does not return the parameter name or the raw encoded query. A missing parameter would return null, but q is present in this address.
Set 2: Design reliable API features10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

An API caps an application at 80 calls per minute. Requests above that limit receive 429. What does that status mean?
  1. The requested record is gone.
  2. Too many requests were made.
  3. A full replacement is required.
  4. The endpoint moved for good.
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A search must send the exact value "A+B & C". What code sets that value without treating its punctuation as URL structure?
  1. url.search = "q=" + "A+B & C";
  2. url.hash = "q=" + "A+B & C";
  3. url.searchParams.set("q", "A+B & C");
  4. url.pathname += "?q=" + "A+B & C";
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

An API record has a title containing literal <b> text, a javascript: link, and remaining: 0. The page must show the literal title, permit only ordinary web links, and preserve the count. What rendering plan meets all three needs?
  1. Use textContent, check HTTP(S) URLs, and default the count with ??.
  2. Use innerHTML, check HTTP(S) URLs, and default the count with ??.
  3. Use textContent, assign every href, and default the count with ??.
  4. Use textContent, check HTTP(S) URLs, and default the count with ||.
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

Two readers view the same UTC instant using Intl.DateTimeFormat with a fixed en-US locale but no timeZone option. Their displayed clock times differ. What explains the difference?
  1. The locale picks each reader’s UTC offset.
  2. The Date changes its stored instant per device.
  3. The Z suffix is ignored without timeZone.
  4. The formatter uses each device’s time zone.
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A search returns valid JSON with an empty results array. Its handler shows the generic error message and keeps the button disabled. What state transition fits this outcome?
  1. Show empty success, retain loading, and keep requesting pages.
  2. Show service failure, clear loading, and retry without a limit.
  3. Show empty success, clear loading, and restore the control.
  4. Show data success with old results and leave the control disabled.
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A dashboard loads an account in 400 ms, then needs its returned ID to load a team in 200 ms. Independent alerts take 700 ms and may fail without hiding account data. What arrangement supports that behavior, and about how long does it take when every read succeeds?
  1. Start all three together and reject the view on any failure; about 700 ms.
  2. Run account then team beside alerts, handling branches separately; about 700 ms.
  3. Run account then team then alerts with one shared catch; about 1300 ms.
  4. Run account beside alerts, then start team after both succeed; about 900 ms.
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

A cross-origin JSON PATCH uses credentials: "include". Preflight permits it. The final response has an allow-origin wildcard and allows credentials, so JavaScript cannot read it. The server also assumes CORS makes user checks unnecessary. What response and access policy repairs this design?
  1. Keep the wildcard, drop credentials permission, and authorize each action.
  2. Name the page origin, keep credentials permission, and trust CORS as authorization.
  3. Keep the wildcard and credentials permission, but authorize each action.
  4. Name the page origin, keep credentials permission, and authorize each action.
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A provider documents a map key as suitable for public browser use. What configuration limits the sites, API operations and total usage allowed for that key?
  1. Restrict domains and APIs, and set usage quotas.
  2. Restrict domains and APIs, but leave usage unlimited.
  3. Restrict APIs and quotas, but allow every domain.
  4. Restrict domains and quotas, but allow every API.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A draft loader parses saved text and immediately calls .map. Some users have valid JSON {"version":1,"items":[]} left by older code, and others have damaged text. What restoration plan handles both cases?
  1. Catch only write failures and use every parsed value as an array.
  2. Replace JSON.parse with JSON.stringify before calling .map.
  3. Catch read/parse failures and validate or convert the saved shape.
  4. Use ?? [] after parsing and assume non-null values are arrays.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A laptop reports navigator.onLine === true, but an API call rejects. What should the page infer about connectivity and handle next?
  1. The API is reachable; interpret the rejection only as invalid JSON.
  2. A network is detected, but the API can still be unreachable; handle the request failure.
  3. The API is unreachable; change the browser’s online flag to false.
  4. The API is reachable; retry immediately until it returns a response.
Show answerHide answer

Save this lesson to see this answer.

Set 3: Follow data through the interface10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A fetch call returns a Response with status 502. The code has a catch handler but never checks response.ok. Why might its HTTP-error message never appear?
  1. An HTTP error rejects only after the catch handler returns.
  2. An HTTP error fulfills fetch; the code must inspect its status.
  3. A 502 response is hidden until its JSON body has been read.
  4. A catch handler receives server statuses only with no-cors.
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A documented delete endpoint returns 204 on success. What should the page do before attempting to parse JSON?
  1. Recognize 204 as failure and repeat the same delete.
  2. Recognize 204 as success and parse an empty object.
  3. Recognize 204 as redirection and fetch the same URL.
  4. Recognize 204 as success and skip the body read.
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A new search appends its items to the old results. A separate "Load more" button should keep appending pages. How should the rendering behavior differ?
  1. Clear for a new search; append for another page.
  2. Append for a new search; clear for another page.
  3. Clear on both actions before adding their results.
  4. Append on both actions and remove only empty items.
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

Two independent reads take about 240 ms and 680 ms. Ignoring overhead, how long should awaiting both through Promise.all take?
  1. About 920 ms.
  2. About 240 ms.
  3. About 680 ms.
  4. About 440 ms.
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A search for "lo" starts, then a search for "lotus" starts. An older completion can hide the new loading message, and an older failure can replace newer results. Cancellation is unavailable in the request wrapper. What update policy keeps the whole screen tied to the current search?
  1. Only successful calls compare their number before rendering.
  2. Only failed calls compare their number before showing errors.
  3. Only the latest call may update results, errors or loading state.
  4. Each call clears the list whenever its own request finishes.
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

From another origin, a page sends a JSON POST with Content-Type: application/json. No preflight permission is cached. What must the browser check before sending that POST?
  1. A GET response containing the same JSON as the planned POST.
  2. An OPTIONS response allowing the origin, method and headers.
  3. An OPTIONS request containing the allow-origin response header.
  4. A POST response declaring the page has disabled same-origin rules.
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

A multi-step form should survive reloads in its tab but end with that tab’s session. What storage choice fits?
  1. Use localStorage and leave the entry until code removes it.
  2. Keep progress only in an in-memory JavaScript variable.
  3. Use localStorage and clear the entry on every page load.
  4. Use sessionStorage to preserve the tab’s current progress.
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A cache expires after 6 minutes. It was saved at 09:12:00 and read at 09:19:30. How should the app treat it?
  1. It is 450,000 ms old and needs fresh data.
  2. It is 75,000 ms old and can be used as fresh.
  3. It is 450,000 ms old and can be used as fresh.
  4. It is 7,500 ms old and needs fresh data.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A weather app works at http://localhost but its location feature is missing when opened on a phone at an HTTP network address. The app also stops working when desktop users deny location. What design addresses both failures?
  1. Retry location on page load, then hide city entry after a denial.
  2. Serve over HTTPS, detect Geolocation, and keep city entry available.
  3. Check the browser name, then request location with no waiting limit.
  4. Keep HTTP, set high accuracy, and remove permission-state checks.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A copy handler awaits navigator.clipboard.writeText(text). At what point should it show "Copied!"?
  1. After that promise fulfills.
  2. As soon as writeText returns.
  3. When feature detection passes.
  4. Right when the user clicks.
Show answerHide answer

Save this lesson to see this answer.

Set 4: Requests, results and browser features10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A response has status 403. What does that status tell the page?
  1. The server could not receive the request at all.
  2. The server needs the resource URL to be redirected.
  3. The server understood the request but refused it.
  4. The server accepted the request with an empty body.
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

An API returns 200 with {"items":[{"name":"Cedar"}]}. What assignment stores the first item’s name after const response = await fetch(url)?
  1. const name = (await response.json()).items[0].name;
  2. const name = response.json().items[0].name;
  3. const name = (await response.json())[0].items.name;
  4. const name = (await response.text()).items[0].name;
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

An endpoint accepts a JSON body. What value should body receive when sending { label: "Read" }?
  1. JSON.parse({ label: "Read" })
  2. String({ label: "Read" })
  3. { label: "Read" }.toString()
  4. JSON.stringify({ label: "Read" })
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

An API returns { remaining: 0, owner: null }. How can the page display the remaining count while using "Unknown" for the missing owner name?
  1. data.remaining || "n/a"; data.owner?.name ?? "Unknown";
  2. data.remaining ?? "n/a"; data.owner?.name ?? "Unknown";
  3. data.remaining ?? "n/a"; data.owner.name ?? "Unknown";
  4. data.remaining || "n/a"; data.owner.name || "Unknown";
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

An API documents amount: 3785, currency: "USD" as integer minor units. What number should go into the currency formatter?
  1. 3785
  2. 37.85
  3. 378.5
  4. 0.3785
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A search disables its button, then awaits a request. The button is re-enabled only after rendering successful results. A failed request leaves it disabled. Where should the shared re-enable statement go?
  1. In the success branch after clearing the status.
  2. In a timer started before checking the response.
  3. In a catch block that replaces all success cleanup.
  4. In a finally block around the awaited work.
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

A page is at https://studio.example.org/edit. What is the origin of that page?
  1. https://studio.example.org
  2. https://studio.example.org/edit
  3. https://example.org
  4. http://studio.example.org
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A front-end build reads a secret provider key from an ignored environment file and sends it in an HTTPS request header. A visitor copies the key from Network. What change protects a replacement key from browser visitors?
  1. Remove the ignored file and keep the same downloaded build.
  2. Rebuild with a shorter variable name and keep the same header.
  3. Revoke the exposed key and make a server add its replacement.
  4. Put a replacement key in the request body and remove the header.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

After localStorage.setItem("visits", 8), what is the value of localStorage.getItem("visits") + 1?
  1. "81"
  2. 9
  3. "9"
  4. 81
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A location request fails with geolocation error code 1. What user-facing response fits the failure?
  1. Explain that the location timed out and repeat at once.
  2. Explain that no position exists and hide the weather form.
  3. Explain that location was denied and offer city entry.
  4. Explain that no position was available and offer another attempt.
Show answerHide answer

Save this lesson to see this answer.

Stuck on your own question? Homework Help

Key Terms

68 Key Terms, each with its definition

A

AbortController
An AbortController supplies a signal for a cancellable operation and can request cancellation by calling its abort method.
The search creates an AbortController and passes its signal to fetch before a later action cancels it.
AbortSignal
An AbortSignal connects cancellation or a time limit to an asynchronous operation such as fetch and its ongoing body reading.
An AbortSignal from AbortSignal.timeout(4000) limits a request to four seconds of active time.
Access token
An access token is a credential that grants defined access for a user or session, allowing its holder to make permitted requests.
The request’s Authorization header carries an access token for the signed-in user’s permitted operation.
API key
An API key is a credential identifying a calling application so a provider can control access, count usage and apply limits or billing.
A browser-visible API key can be copied, so a secret provider key must stay on the calling server.

B

Baseline
Baseline is MDN’s feature-availability summary for major browsers, used alongside detailed compatibility and requirement information.
Checking Baseline helps plan browser testing before the page depends on a newly learned browser API.

C

Cache
A cache is a saved copy of data used to avoid repeating work or requests, with an app-defined policy for deciding when it is fresh.
A weather cache can show a recent forecast immediately while an expired entry triggers a fresh request.
Clipboard API
The Clipboard API lets a page asynchronously read or write system clipboard content, subject to secure-context and browser access rules.
A copy button uses the Clipboard API after a click and waits before showing its success message.
CORS
CORS is the HTTP-header mechanism that lets a server permit browser scripts on other origins to read its responses.
The API uses CORS to let a page on a named site read its weather data from a different host.
Cross-site scripting
Cross-site scripting is the execution of untrusted script in a page, which can occur when external strings are interpreted as HTML.
Using textContent for API titles removes the HTML interpretation that can permit cross-site scripting.

D

Debouncing
Debouncing delays an operation until repeated events pause, resetting the wait after each event so a burst produces fewer calls.
Debouncing a search field avoids sending a separate request for every keystroke in a quickly typed word.

E

Empty state
An empty state is the interface shown after a successful operation returns no matching data, distinguishing that outcome from failure.
The empty state says "No records match your filter" after the API returns a valid empty array.
Endpoint
An endpoint is an API address that accepts a documented request for a resource or operation, often using a particular HTTP method.
The notes endpoint accepts a POST to create a note and returns the new record’s identifier.
Expiry
An expiry is the age or time after which an app no longer treats a saved value as fresh, even if that value remains in storage.
A ten-minute expiry makes an app compare the current time with the time saved alongside its cached response.
Exponential backoff
Exponential backoff increases the delay between retry attempts by a multiplying factor, reducing repeated load during a temporary failure.
Exponential backoff might wait one, two and four seconds between a bounded sequence of retry attempts.

F

Fallback
A fallback is an alternative way to complete a task when the preferred feature is unsupported, refused or unable to finish.
Selecting a link field for keyboard copying provides a fallback when automatic clipboard access fails.
Feature detection
Feature detection checks whether a capability is available before code uses it, letting the page select a supported route or fallback.
Feature detection with "geolocation" in navigator decides whether the page can offer device location.
FormData
FormData is a browser object that collects form fields and files for submission, allowing fetch to construct a multipart request body.
Passing FormData as the body lets the browser send the selected image beside the form’s text fields.

G

Geolocation
Geolocation is a browser API that obtains an estimated device position with the user’s permission and reports success or failure.
Geolocation can supply coordinates for a nearby forecast, with typed city entry available after refusal.

H

Header
A header is a named value attached to a request or response that describes the exchange, its content or its access requirements.
A Content-Type header tells the receiving program that the accompanying body contains JSON.
HTTP request
An HTTP request is a message from a client to a server with a method, URL, headers and, for some operations, a body.
The HTTP request asks for /books and includes a query parameter that limits the number of results.
HTTP response
An HTTP response is a server’s reply to a request, containing a status code, headers and usually a body with data or an error.
The HTTP response reports 404 and explains in its body that the requested book was not found.
HttpOnly
HttpOnly is a cookie attribute that prevents page JavaScript from reading that cookie while it can still accompany matching requests.
A cookie marked HttpOnly differs from localStorage data, which scripts on the origin can read.

I

Idempotence
Idempotence means that repeating an identical operation has the same intended effect on server state as performing it once.
Deleting a note twice illustrates idempotence: the note remains absent even if the second status differs.
IndexedDB
IndexedDB is the browser’s asynchronous database for larger structured data and files that do not fit small Web Storage tasks well.
A page with a large structured collection can use IndexedDB instead of repeatedly writing it as one storage string.
Intl.NumberFormat
Intl.NumberFormat is a JavaScript formatter that creates readable number, currency, percent or unit strings for a chosen locale.
The page reuses Intl.NumberFormat for every price instead of rebuilding a currency string for each item.

J

JSON
JSON is a text format for structured data, including objects and arrays, that must be parsed before code uses its nested values.
The page parses JSON and reads the array inside its results property before building list items.

L

Live region
A live region is a page area whose content changes can be announced by assistive technology without moving keyboard focus.
A live region with role="status" announces "Loading…" and the later search-result message.
Loading state
A loading state tells the reader that an asynchronous operation is in progress while the page waits for its result.
The loading state shows "Searching…" before the request begins and clears when the request finishes.
Locale
A locale identifies language and regional formatting conventions used to display values such as dates, numbers and money.
The en-US locale writes a date differently from en-GB even when both format the same instant.
localStorage
localStorage is the origin’s persistent Web Storage area, shared by its tabs and retained beyond browser closure until removed or cleared.
A theme saved in localStorage can be restored on the next visit and read by another same-origin tab.
Location accuracy
Location accuracy describes the estimated horizontal uncertainty around a reported position, measured in meters rather than degrees.
Location accuracy of 60 meters describes the estimated radius of uncertainty around the reported position.

M

Minor currency unit
A minor currency unit is a subdivision of a currency’s main unit, such as a cent for USD, used by some APIs for integer amounts.
When an API documents USD minor currency units, the integer 4680 represents 46.80 dollars.
Mixed content
Mixed content occurs when a secure page requests an insecure resource; browsers block HTTP fetch calls made by HTTPS pages.
An HTTP forecast URL causes a mixed content failure when the weather page itself is loaded over HTTPS.
Multipart boundary
A multipart boundary is the delimiter used to separate fields and files in a multipart body, identified in its content-type header.
The browser supplies the multipart boundary when the page sends FormData without setting Content-Type itself.

N

Nullish coalescing
Nullish coalescing supplies a fallback with ?? only when its left-hand value is null or undefined, preserving valid zeros.
Nullish coalescing keeps an API count of zero instead of replacing it with the text "not available".

O

Opaque response
An opaque response hides its status details, headers and body from page code and exposes a status value of zero.
A no-cors fetch gives an opaque response, so the page cannot extract the JSON it hoped to display.
Optional chaining
Optional chaining safely stops a property access when the value before ?. is null or undefined, returning undefined.
Optional chaining lets book.author?.name handle a book whose author object is missing from the response.
Origin
An origin is the combination of a URL’s scheme, host and port, which the browser uses to define several access boundaries.
Two paths on one HTTPS host share an origin, but changing that host or its port creates another origin.

P

Pagination
Pagination divides a result collection into smaller groups that an API returns separately, usually through page or cursor parameters.
Pagination lets a "Load more" button request the next group while retaining the items already displayed.
Parse error
A parse error occurs when text cannot be interpreted in the expected format, such as an HTML page passed to a JSON reader.
An empty 204 body causes a JSON parse error even though the server successfully completed the operation.
Permission
A permission is a browser-managed decision allowing or refusing a page access to a protected feature such as device location.
A remembered permission denial can make a location request fail without displaying a second prompt.
Preflight
A preflight is a browser-sent OPTIONS request that checks cross-origin permission for an intended method and request headers.
A JSON POST can need a preflight before the browser sends the record that the page wants to create.
Promise.all
Promise.all combines input promises into one result array when all fulfill and rejects as soon as an input promise rejects.
The page uses Promise.all for two independent reads whose results must both be available for the display.
Promise.allSettled
Promise.allSettled waits for every input promise and returns an outcome object for each, including its success or failure.
Promise.allSettled lets a dashboard display two successful panels while explaining a third panel’s failure.

Q

Query parameter
A query parameter is a named value in the part of a URL after ?, used by an endpoint for inputs such as searches or page limits.
The query parameter limit=12 asks the search endpoint to return no more than twelve results.

R

Race condition
A race condition is a result that depends on the order asynchronous work finishes, such as an older search replacing newer results.
A request-number check prevents a race condition when a slower earlier search finishes after the current one.
Rate limit
A rate limit caps how many operations a client or credential may perform in a time interval, helping a service control usage.
A search rate limit can be exceeded by one request per keystroke, so debouncing reduces unnecessary calls.
Rendering
Rendering turns data into visible page content, such as creating a list element for each object in an API’s results array.
Rendering a new search starts by clearing the previous list, then appending the current result items.
Request body
A request body carries submitted content to a server, such as a serialized JSON record or form fields in a create request.
The request body contains a note’s title and text, while the method specifies that the note should be created.
Response body
A response body is the content sent after the response headers, which can hold JSON, text, binary data or no content at all.
The page reads the response body once and keeps the resulting object for both rendering and filtering.
Response object
A Response object represents the headers and status returned by fetch and supplies methods for reading the response body.
The Response object has status 200, but the page still awaits json() to obtain the book data.
Retry-After
The Retry-After header tells a client when to try again, using a delay in seconds or an HTTP date on a suitable response.
A Retry-After value of 15 asks the page to wait fifteen seconds before another request.

S

Same-origin policy
The same-origin policy is a browser security boundary that restricts how a script can read resources belonging to another origin.
The same-origin policy makes a cross-origin fetch depend on the API server’s CORS reading permission.
Secure context
A secure context is a browser context considered trustworthy for restricted APIs, usually provided by HTTPS or a qualifying local origin.
A secure context at localhost supports development, while a plain HTTP network address may not qualify.
Serialization
Serialization converts a value into a format that can be stored or transmitted, such as turning a JavaScript object into JSON text.
Serialization with JSON.stringify preserves a note’s fields when they are sent as a JSON request body.
sessionStorage
sessionStorage is Web Storage scoped to an origin and a tab’s page session, retaining values across reloads during that session.
A form uses sessionStorage for progress that should survive a reload without becoming shared persistent state.
Status code
A status code is a three-digit HTTP value that reports a request’s outcome, such as success, refusal or a server problem.
A status code of 201 tells the page that the server created a resource in response to the request.
Storage event
A storage event notifies other eligible same-origin contexts of a storage change; a localStorage writer does not receive its own event.
A storage event updates the theme in another tab while the writing tab applies the theme directly.
Storage quota
A storage quota is a browser-imposed limit on stored data; exceeding available Web Storage space can make a write throw an error.
An app that keeps a list in memory catches a storage quota error and keeps using that list even when it cannot save it.
Synchronous operation
A synchronous operation completes before the next statement continues, so a lengthy storage call can block the page’s main thread.
A large Web Storage write is a synchronous operation that can delay handling the next user interaction.

T

textContent
The textContent property reads or sets an element’s text without interpreting the supplied string as HTML markup.
Assigning a title to textContent displays its angle brackets literally instead of creating an HTML element.
Time zone
A time zone determines the local calendar date and clock time used to display an instant, including applicable offset rules.
An explicit UTC time zone makes every reader see an event’s clock time in UTC instead of their device’s zone.

U

Unix timestamp
A Unix timestamp measures elapsed time from January 1, 1970, UTC; the documented unit may be seconds or milliseconds.
A Unix timestamp in seconds needs multiplication by 1000 before it becomes a JavaScript Date value.
URL encoding
URL encoding represents characters safely inside URL components so data punctuation is not mistaken for address structure.
URL encoding keeps the ampersand in a band’s name inside the query value instead of starting a new parameter.
User activation
User activation is browser-recognized interaction, such as a recent click, that can be required before a restricted feature is allowed.
Calling clipboard writing directly in a click handler supplies user activation where the browser requires it.
UTC
UTC is the shared time reference used to identify instants across time zones, represented by Z at the end of an ISO date-time.
The API returns an instant in UTC, and the page formats that instant for a reader in another time zone.

W

Web API
A web API exposes operations that a program calls through URLs to read or change data held by another system.
A weather web API lets a page request a forecast for a city without loading a new page.
Web Storage
Web Storage provides synchronous browser key–value stores for small string values, separated by origin and selected lifetime.
Web Storage keeps a serialized settings object that the page restores when it starts again.

About this lesson

By StudeliReport a mistake

Make your own Study Materials

Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.

Get Started