Web APIs Cheatsheet

Fetch and HTTP

Use this Web APIs reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Basic Fetch

// GET (default)
const res = await fetch('/api/data');
const json = await res.json();

// POST with JSON body
const res = await fetch('/api/users', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Alice' }),
});
const data = await res.json();

fetch() Options

OptionTypeDescription
methodstring'GET' 'POST' 'PUT' 'PATCH' 'DELETE' 'HEAD'
headersobject | HeadersRequest headers
bodystring | Blob | BufferSource | FormData | URLSearchParams | ReadableStreamRequest body (not allowed on GET/HEAD)
modestring'cors' (default) 'no-cors' 'same-origin' 'navigate'
credentialsstring'omit' 'same-origin' (default) 'include'
cachestring'default' 'no-store' 'reload' 'no-cache' 'force-cache' 'only-if-cached'
redirectstring'follow' (default) 'error' 'manual'
referrerPolicystring'no-referrer' 'origin' 'strict-origin-when-cross-origin'
signalAbortSignalCancel the request
keepalivebooleanKeep request alive after page unload
prioritystring'high' 'low' 'auto'

Response Object

Property / MethodReturnsNotes
res.okbooleantrue when status 200–299
res.statusnumberHTTP status code
res.statusTextstringe.g. 'OK'
res.headersHeadersIterable headers map
res.urlstringFinal URL after redirects
res.redirectedbooleanWhether a redirect occurred
res.typestring'basic' 'cors' 'opaque'
res.bodyReadableStreamRaw body stream
res.bodyUsedbooleantrue once body consumed
res.json()Promise\<any\>Parse body as JSON
res.text()Promise\<string\>Body as text
res.blob()Promise\<Blob\>Body as Blob
res.arrayBuffer()Promise\<ArrayBuffer\>Body as binary
res.formData()Promise\<FormData\>Body as FormData
res.clone()ResponseClone before consuming body twice

Headers API

const headers = new Headers({ 'Content-Type': 'application/json' });
headers.set('Authorization', 'Bearer token');
headers.append('X-Custom', 'value');
headers.get('content-type'); // 'application/json'
headers.has('Authorization'); // true
headers.delete('X-Custom');

// Iterate
for (const [key, val] of headers) { /* … */ }
headers.forEach((val, key) => { /* … */ });

Request API

const req = new Request('/api/data', {
  method: 'GET',
  headers: { Accept: 'application/json' },
});

req.url;      // full URL string
req.method;   // 'GET'
req.headers;  // Headers object
req.clone();  // clone before passing to fetch

fetch(req).then(/* … */);

Aborting Requests

const controller = new AbortController();
const { signal } = controller;

fetch('/api/slow', { signal })
  .then(res => res.json())
  .catch(err => {
    if (err.name === 'AbortError') console.log('Request aborted');
  });

// Cancel after 5 s
setTimeout(() => controller.abort(), 5000);
// Pass a reason
controller.abort(new Error('User cancelled'));
// AbortSignal.timeout() — no controller needed
const res = await fetch('/api/data', {
  signal: AbortSignal.timeout(3000), // ms
});

Error Handling

fetch() only rejects on network failure; HTTP 4xx/5xx still resolve. Always check res.ok.

async function apiFetch(url, options) {
  const res = await fetch(url, options);
  if (!res.ok) {
    const body = await res.text();
    throw new Error(`HTTP ${res.status}: ${body}`);
  }
  return res.json();
}

Sending FormData and Files

const form = new FormData();
form.append('username', 'alice');
form.append('avatar', fileInput.files[0]);

// Do NOT set Content-Type manually — browser sets multipart boundary
await fetch('/api/upload', { method: 'POST', body: form });

Streaming Responses

const res = await fetch('/api/stream');
const reader = res.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  console.log(decoder.decode(value, { stream: true }));
}

Streaming with async iteration (modern)

const res = await fetch('/api/stream');
for await (const chunk of res.body) {
  console.log(new TextDecoder().decode(chunk));
}

Uploading with Progress (XMLHttpRequest)

fetch() has no upload-progress API yet. Use XMLHttpRequest for upload progress.

const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', e => {
  if (e.lengthComputable) console.log(e.loaded / e.total);
});
xhr.open('POST', '/api/upload');
xhr.send(formData);
xhr.onload = () => console.log(xhr.status, xhr.responseText);

XMLHttpRequest Quick Reference

const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/data', true /* async */);
xhr.responseType = 'json'; // '', 'arraybuffer', 'blob', 'document', 'json', 'text'
xhr.timeout = 5000;        // ms
xhr.setRequestHeader('Accept', 'application/json');

xhr.onload = () => console.log(xhr.status, xhr.response);
xhr.onerror = () => console.error('Network error');
xhr.ontimeout = () => console.error('Timeout');
xhr.onprogress = e => console.log(e.loaded, e.total);
xhr.onreadystatechange = () => {
  // readyState: 0 UNSENT, 1 OPENED, 2 HEADERS_RECEIVED, 3 LOADING, 4 DONE
};
xhr.send(null); // or body
xhr.abort();

CORS Essentials

ScenarioHeaders Required
Simple cross-origin GET/POST (text/plain, form types)Access-Control-Allow-Origin on response
Custom headers or PUT/DELETE (preflight)Server must respond to OPTIONS with Access-Control-Allow-Methods, Access-Control-Allow-Headers
Cookies cross-origincredentials: 'include' + server Access-Control-Allow-Credentials: true + specific (not *) origin
// Include cookies / auth headers cross-origin
fetch('https://api.example.com/data', { credentials: 'include' });

Common Patterns

// Retry with exponential backoff
async function fetchWithRetry(url, opts, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const res = await fetch(url, opts);
      if (!res.ok && res.status >= 500) throw new Error(res.status);
      return res;
    } catch (err) {
      if (i === retries - 1) throw err;
      await new Promise(r => setTimeout(r, 2 ** i * 500));
    }
  }
}

// JSON helper
const get = url => fetch(url).then(r => r.ok ? r.json() : Promise.reject(r));

// Base URL wrapper
const api = (path, opts) => fetch(`https://api.example.com${path}`, {
  ...opts,
  headers: { Authorization: `Bearer ${token}`, ...opts?.headers },
});

Caching Strategies

cache valueBehavior
'default'Uses browser cache with HTTP semantics (ETags, max-age)
'no-store'Never cache; never use cached response
'reload'Always fetch from network; store result in cache
'no-cache'Validate with server (conditional request) even if cached
'force-cache'Return cached response even if stale
'only-if-cached'Return cache or fail (only with mode: 'same-origin')

Server-Sent Events (EventSource)

const es = new EventSource('/api/events');
// named event
es.addEventListener('update', e => console.log(JSON.parse(e.data)));
// unnamed / message event
es.onmessage = e => console.log(e.data);
es.onerror = e => console.error(e);
es.close();

// With credentials
const es2 = new EventSource('/api/events', { withCredentials: true });